Summary
Hey @unadlib 👋
First, thanks a million for this library !
I've implemented an undo/redo feature (in a react app) with complex fields, where each field's state has to be undoable and depends on several metadata.
To ensure my undo/redo implementation relies only on my frontend, I have to store a complex object in my history stack.
Therefore the fact that travels relies on JSON patches makes a lot of sense to me, performance-wise 🙏
I noticed I had a hard time using the use-travel hook for my needs, mainly because I didn't need the reactivity layer you brought there.
I ended up using travels over use-travel.
Therefore, I wanted to share this case for your knowledge, as a thank you for your work.
Hoping it may bring some food for thoughts 👍
Tech ecosystem
react app
react-hook-form as a form manager
travels for undo/redo
I think any app with form management should avoid having 2 sources of truth for their data, therefore, it is likely travels will be there only to safely store changes.
Why use-travel didn't answer my need
Reactive value not needed
Because I already had a form manager integrated, travels only comes as a layer on top of my data.
My app does not consume the state provided by travels/use-travel as a reactive value.
Binding to user interaction
I bind travels forward and back navigations to user interaction, then immediately propagate a state update to my form manager.
Therefore, the user interaction callback is the only time I need to consume travels state :
const travelOnKeyDown = (event: KeyboardEvent) => {
if (!travelsRef.current) return;
if (isUndoKeyboardEvent(event)) {
event.preventDefault();
if (!travelsRef.current.canBack()) return;
travelsRef.current.back();
onChange(travelsRef.current.getState()); // react-hook-form binding
return;
}
if (isRedoKeyboardEvent(event)) {
event.preventDefault();
if (!travelsRef.current.canForward()) return;
travelsRef.current.forward();
onChange(travelsRef.current.getState()); // react-hook-form binding
return;
}
};
Imperative API over watchers
Because travels brings an imperative API, it makes for a simpler implementation for my use case.
As you can see in the previous example I shared :
if (!travelsRef.current.canBack()) return;
travelsRef.current.back(); // instantly navigates to previous state
onChange(travelsRef.current.getState()); // this is the expected previous state
Having an imperative API allows me to navigate inside travel history then get the updated state, in sync.
With use-travel, I would have to split the navigation and the state propagation, because state wouldn't be updated from within my callback loop.
if (!travelsRef.current.canBack()) return;
travelsRef.current.back(); // navigates to previous state
onChange(state); // state is a stale value
Summary
Hey @unadlib 👋
First, thanks a million for this library !
I've implemented an undo/redo feature (in a react app) with complex fields, where each field's state has to be undoable and depends on several metadata.
To ensure my undo/redo implementation relies only on my frontend, I have to store a complex object in my history stack.
Therefore the fact that
travelsrelies on JSON patches makes a lot of sense to me, performance-wise 🙏I noticed I had a hard time using the
use-travelhook for my needs, mainly because I didn't need the reactivity layer you brought there.I ended up using
travelsoveruse-travel.Therefore, I wanted to share this case for your knowledge, as a thank you for your work.
Hoping it may bring some food for thoughts 👍
Tech ecosystem
reactappreact-hook-formas a form managertravelsfor undo/redoI think any app with form management should avoid having 2 sources of truth for their data, therefore, it is likely
travelswill be there only to safely store changes.Why
use-traveldidn't answer my needReactive value not needed
Because I already had a form manager integrated,
travelsonly comes as a layer on top of my data.My app does not consume the
stateprovided bytravels/use-travelas a reactive value.Binding to user interaction
I bind
travelsforwardandbacknavigations to user interaction, then immediately propagate a state update to my form manager.Therefore, the user interaction callback is the only time I need to consume
travelsstate :Imperative API over watchers
Because
travelsbrings an imperative API, it makes for a simpler implementation for my use case.As you can see in the previous example I shared :
Having an imperative API allows me to navigate inside travel history then get the updated state, in sync.
With
use-travel, I would have to split the navigation and the state propagation, because state wouldn't be updated from within my callback loop.