Current Change Event
Basic usage
By default Trrack keeps a pointer the latest added node. This can be accessed using trrack.current
. Using undo
, redo
, and todo
will update this pointer to the appropriate node. Trrack emits a currentChange
event whenever current node changes due to any reason.
To respond to the currentChange
event you can register a listener. The currentChange
listener gets an optional argument which is the trigger
for the current change.
import { initializeTrrack } from '@trrack/core';
const trrack = initializeTrrack({ ... });
trrack.currentChange(() => {
// Do something...
});
Cleaning up
currentChange
function returns an unsubscribe function which can be used to remove the listener to avoid memory leaks.
import { initializeTrrack } from '@trrack/core';
const trrack = initializeTrrack({ ... });
const unsubscribe = trrack.currentChange(() => {
// Do something...
});
// Call unsubscribe to remove the listener
unsubscribe();
Advanced usage with state management libraries
Current change event is the primary way to interact with the store from a state management library like redux
or pinia
.
currentChange
event is used to sync the state of the store with current state from Trrack.
A general workflow for such integration looks like following:
- Initialize store
- Initialize trrack with initialState (possibly from store)
- Setup store update actions to also inform Trrack about the udpates
- Register
currentChange
listener to update the store state with the current state from Trrack in case oftraversal
.
Let's assume we have a provenance graph which looks as follows:
|
A (State 1)
|
B (State 2)
|
C (State 3) <-- Current
|
The state of the store is the same as State 3
.
If we execute trrack.undo()
at this point, the graph will be updated:
|
A (State 1)
|
B (State 2) <-- Current
|
C (State 3)
|
However, our store state is still State 3
. Inside the currentChange
listener we can update the store state with the current state from Trrack.
trrack.currentChange(() => {
const newState = trrack.getState(); // gets the state from current node
store.update(newState); // update the store state
});
This works great when we are traversing the graph. However, if we execute trrack.apply()
when current
is pointing to State 3
the store updates to State 4
. Our state update actions also inform trrack about the new state, and the graph will be updated:
|
A (State 1)
|
B (State 2)
|
C (State 3)
|
D (State 4) <-- Current
|
Since a new node was added to Trrack and current pointer changed to point to it, the currentChange
event is triggered, which updates the store, and may cause re-rendering.
Trrack passes trigger
argument to the currentChange
listener. If trigger
is new
we can skip the store update. The value for trigger
can be traversal
or new
. traversal
means that the current node was changed due to a undo
, redo
, or to
command. new
means that the current node was changed due to a apply
command. This way we can avoid updating the store state when the current node is changed due to addition of new node.
trrack.currentChange((trigger: Trigger) => {
if (trigger === 'new') return; // skip store update
const newState = trrack.getState(); // gets the state from current node
store.update(newState); // update the store state
});
Such a use case can be found very frequently when two state containers update each other. To handle such case, the currentChange
function accepts a second optional boolean argument which is skipOnNew
.
Passing true
to skipOnNew
will skip the store update when the current node is changed due to addition of new node.
trrack.currentChange((trigger: Trigger) => {
/** do not need this anymore */
// if (trigger === 'new') return;
const newState = trrack.getState(); // gets the state from current node
store.update(newState); // update the store state
}, true); // skip store update when current node is changed due to addition of new node