zundo icon indicating copy to clipboard operation
zundo copied to clipboard

execute custom function on saving state with activated cool-off period

Open TimKraemer opened this issue 2 years ago • 8 comments

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

TimKraemer avatar Jul 20 '22 14:07 TimKraemer

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

charkour avatar Jul 21 '22 12:07 charkour

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

TimKraemer avatar Jul 21 '22 12:07 TimKraemer

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}
    </>
  );
};

charkour avatar Jul 21 '22 13:07 charkour

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

TimKraemer avatar Jul 21 '22 13:07 TimKraemer

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!

charkour avatar Jul 22 '22 16:07 charkour

If I can be of any help - I'd gladly take a look, if you'd give me a hint where to start :)

TimKraemer avatar Jul 29 '22 20:07 TimKraemer

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!

charkour avatar Aug 01 '22 13:08 charkour

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!

charkour avatar Aug 08 '22 17:08 charkour

This is released in v2 of zundo.

you can try this out with npm i zundo@beta

charkour avatar Sep 23 '22 02:09 charkour