zundo
zundo copied to clipboard
execute custom function on saving state with activated cool-off period
Hi, amazing middleware - I absolutely love it! I'm trying to find a way to find a way to execute a custom function whenever a state is saved, while cool-off period is set.
For example: Whenever my user edits the store by using my app I will generate an unique url to load exactly that state. I could just subscribe to my store and to it there, but since I'm using a cool-off period of 2000ms it would be ideal, if I could just subscribe to that saving event and only then generate my unique url,
Any ideas how I would approach that?
Best wishes, Tim
Hi @TimKraemer, glad you here you love the middleware!
To clarify the context of your use case, whenever a user makes an edit to the store, a unique URL will be generated for that state and will have a cool-off period of 2000ms before generating a new URL for the next new state?
My initial thought is that you could use setTimeout(() => generateUrlFromState(store.getState(), 2000)
, but the stored state in the zundo store may be different from the store state after 2000ms. I think the best would be to add an optional callback that can be passed into the store that is called when the zundo store is set. Right now, the library doesn't support that so we could add that as a feature.
What do you think?
Charles
Yes @charkour, you got the idea! The timeout is how I'm currently mitigating the issue, but it's not ideal - also it kind of prevents me from reusing the links elegantly, when I undo/redo my state... A callback like that would be amazing!
Best, Tim
I can see what I can do tonight.
Would you be able to provide the callback when you create the store and pass middleware options, or do you need to pass the callback when you call the useStoreWithUndo()
hook?
For a little more context:
const useStoreWithUndo = create((set) => ({
bears: 0,
}),
// Your callback here at creation?
{ onSave: (state) => myCallback(state) }
);
const App = () => {
// Your callback here at hook?
const { bears } = useStoreWithUndo(selector, { onSave: (state) => myCallback(state) });
return (
<>
bears: {bears}
</>
);
};
both options are possible - I trust your instincts, which one would be "more beautiful" in a code structural sense.
Instinctively I would think it's nicer to have this in my App
context to not litter the useStore
function with unrelated code
I like the idea of keeping it within the App
context. This will be harder to do, but I think it's cleaner. I'll look into this more over the weekend.
Thanks for your patience and for the great suggestion!
If I can be of any help - I'd gladly take a look, if you'd give me a hint where to start :)
Hi Tim!
I spent some time trying to figure out how to do this with v1 of the package, and I was unable to figure it out with us wanting to pass in the callback when useStore
is called within the App context. I'm working on v2 which I believe should make this possible.
It would be great if you would like to take a look and implement this feature in v1. Perhaps you could find a way to pass the callback when useStore
is called. If that's not possible, what I think could work is to add two new fields to the store state in https://github.com/charkour/zundo/blob/main/src/factory.ts called setOnSave
and onSave
. onSave
would be called in handleStoreUpdates
in factory.ts
. This API would be used in user-land similar to this.
const useStoreWithUndo = create((set) => ({
bears: 0,
}),
);
const App = () => {
const { bears, setOnSave } = useStoreWithUndo(selector);
useEffect(() => {
setOnSave(myCallback);
}, []);
return (
<>
bears: {bears}
</>
);
};
You can make a PR will the API you would like! I'd like to keep focusing on v2 and will implement this feature there. Thank you!
I was able to solve this in v2 of zundo. Will let you know when the beta is released. Should be by the end of the week. Thanks!
This is released in v2 of zundo.
you can try this out with npm i zundo@beta