DEV Community

vaukalak
vaukalak

Posted on

Easy history management for React with Mlyn

In the introduction to mlyn post, I've shown an example of how easy is to create a TodoMVC app within it. In this post, I'd like to demonstrate how 2-way binding can help to setup history management. This is how the app would look like:
Todo MVC with history
You can see full code on this codesandbox
The thing we want to track is todos field of the store:

const state$ = useSubject({
  todos: [],
  newTitle: ""
});
Enter fullscreen mode Exit fullscreen mode

Since all parts of a mlyn store are 2-way bindable, we can easily pass it to the tracking function:

const [history] = createHistory(state$.todos);
Enter fullscreen mode Exit fullscreen mode

createHistory is an utility from mlyn-history package. Within the returned history object we can jump to any step of the tracked state. Lets write a component for that:

const History = seal(({ history }) => {
  // let store past and future to local storage.
  useSyncronize(history.past$, "past");
  useSyncronize(history.future$, "future");
  return (
    <>
      <Mlyn.Input
        type="range"
        step="1"
        onChange={(e) => {
          // on input change, jump to a point in history
          history.jumpTo(e.target.value);
        }}
        // subscribe component to history position.
        value$={() => history.past$().length}
        // the range of mutations, indexing starts from 1
        // cause 0 is the initial state which can't be rolled back
        min={1}
        max$={() => history.entries$().length}
        // history with one entry (actual state)
        // is empty, hence can't be modified
        disabled$={() => history.entries$().length === 1}
      />
      <button onClick={history.commit}>COMMIT</button>
    </>
  );
});
Enter fullscreen mode Exit fullscreen mode

And that's it, now every step of the todos state can be easily inspected. I hope the above has convinced you in the power of 2-way binding.

Discussion (0)