fix equality fn type and update docs#144
Conversation
| const { bears, increasePopulation, removeAllBears } = useStoreWithUndo(); | ||
| // See API section for temporal.getState() for all functions and | ||
| // properties provided by `temporal` | ||
| const { undo, redo, clear } = useStoreWithUndo.temporal.getState(); |
There was a problem hiding this comment.
This may be personal preference, but I think it is simpler in the docs to introduce (and recommend) useStore.temporal.getState() prior to something like useTemporalStore. I think most users will not need to access member properties of the temporal object in a reactive way (that is, they'll likely just need undo, redo, clear and not need reactive access to pastStates or currentStates, isTracking, etc. I think introducing it this way may help facilitate a more straightforward mental model of what zundo is doing. But I'm not sure!
There was a problem hiding this comment.
I agree with this, thank you for making this change and for providing an explanation!
| ## Then bind your components | ||
|
|
||
| Use your store anywhere, including `undo`, `redo`, and `clear`! | ||
| ) => useStore(useStoreWithUndo.temporal, selector, equality); |
There was a problem hiding this comment.
For consistency in the docs, I replaced all references to stores created with temporal with useStoreWithUndo. I think this could makes things more clear to readers, instead of referring to the store by multiple names like useStoreWithUndo, originalStore, useStoreA, withTemporal, etc.
There was a problem hiding this comment.
Thanks, I didn't realize I used a different name each time. Oops!
| ); | ||
| ``` | ||
|
|
||
| If converting temporal store to a React Store Hook with typescript, be sure to define the type of |
There was a problem hiding this comment.
This is new -- giving an example of useTemporalStore with partialized state. If users useTemporalState<StoreState> while using partialize as a ZundoOption, they will see a type error. So this is to preempt that kind of error by providing an example of useTemporalState with a partalized store state typescript generic
README.md
Outdated
| `equality?: (pastState: PartialTState, currentState: PartialTState) => boolean` | ||
|
|
||
| For performance reasons, you may want to use a custom `equality` function to determine when a state change should be tracked. You can write your own or use something like [`fast-equals`](https://github.com/planttheidea/fast-equals), [`fast-deep-equal`](https://github.com/epoberezkin/fast-deep-equal), [`zustand/shallow`](https://github.com/pmndrs/zustand/blob/main/src/shallow.ts), [`lodash.isequal`](https://www.npmjs.com/package/lodash.isequal), or [`underscore.isEqual`](https://github.com/jashkenas/underscore/blob/master/modules/isEqual.js). By default, all state changes to your store are tracked. | ||
| Provide an `equality` function to determine when a state change should be tracked. |
There was a problem hiding this comment.
I removed "performance reasons", as I think many reasons to use a custom equality function are not actually for performance reasons (although some are!). I think many instances of using an equality function are to ensure that effectively duplicate state histories are not tracked. For example, by using deep-equality or shallow equality fns. My impression is that the performance considerations may have more to do with which equality fn one chooses, as without one, history is naively added to no matter if shallow or deep equality is true.
There was a problem hiding this comment.
Thanks for the explanation! Could you find a way to include possible reasons someone might use this option? I included performance originally because people asked for that reason and I wanted people to Cmd+F performance in the readme. However, I agree there are other important reasons too, so could you include more of them? Thank you!
There was a problem hiding this comment.
No problem! I expanded the section a little bit, and added back the word performance for easy Cmd+F-ing -- let me know fi you think it is clear or if I should try to expand it more. I'm trying to find the right balance of not bloating the code examples while also trying to be as immediately clear to the reader as possible. If you think it would be even clearer to provide example StoreState interfaces for the various use-cases, I'm happy to add those. But if it seems to be sufficient without them, I think my instinct is to try to stay as lean as possible.
There was a problem hiding this comment.
Thanks for making that change! Striking the balance of keeping docs clear but bloated is difficult and I appreciate you for trying to find that balance too.
| Sometimes multiple state changes might happen in a short amount of time and you only want to store one change in history. To do so, we can utilize the `handleSet` callback to set a timeout to prevent new changes from being stored in history. This can be used with something like [`throttle-debounce`](https://github.com/niksy/throttle-debounce), [`just-throttle`](https://github.com/angus-c/just/tree/master/packages/function-throttle), [`just-debounce-it`](https://github.com/angus-c/just/tree/master/packages/function-debounce), [`lodash.throttle`](https://www.npmjs.com/package/lodash.throttle), or [`lodash.debounce`](https://www.npmjs.com/package/lodash.debounce). This a way to provide middleware to the temporal store's setter function. | ||
|
|
||
| ```tsx | ||
| const withTemporal = temporal<MyState>( |
There was a problem hiding this comment.
It was initially confusing for me that these examples did not use create from zustand. I think it makes sense to keep a common code template for all ZundoOptions API examples, so this was updated here.
|
|
||
| > While `setState`, `subscribe`, and `destroy` exist on `temporal`, you should not need to use them. | ||
|
|
||
| #### **React Hooks** |
There was a problem hiding this comment.
This was removed, as it seemed to be a duplicate of useTemporalStore example earlier in the docs
|
Overall these documentation updates are looking great. I'll give my complete review tomorrow. Thanks! |
charkour
left a comment
There was a problem hiding this comment.
These updates are fantastic, thank you!
| `zundo` has one export: `temporal`. It is used as middleware for `create` from zustand. The `config` parameter is your store created by zustand. The second `options` param is optional and has the following API. | ||
|
|
||
| ### Middleware Options | ||
| ### Bear's eye view: |
There was a problem hiding this comment.
This little easter egg is great!
There was a problem hiding this comment.
Haha nice! I was hoping you'd like it 😆
|
Thank you for reviewing and bringing in these changes! |
This PR updates the types as mentioned here.
I also included some updates to the docs. If you'd prefer I separate these docs updates into a separate PR, I'm happy to do so!
When I was first reading the docs for
zundothere were some points of initial confusion for me, so some of my suggested updates are to clarify those things.Thank you!