State must be transfered between nodes to keep track of data specific to certain events. Within XIBLE, state primarely exists to track values related to "event" nodes. An instance of the FlowState class is provided to each event on a Node. In most cases it is required that this state is passed on to other function calls on the node itself, its inputs and outputs.
Managing state
Let' take a look at a fictional "event" node with two outputs;
- trigger
- value
The purpose of this node is to simply return the value associated to an event called "somevent" which triggered the "trigger" output. For demonstration purposes, we will hook up this node to a "console.log" node. Trigger output to trigger input, value output to value input.
Incorrectly passing values
If the fictional "event" node would simply store the value of the event in a local variable and return that variable when requested on the "value" output, a race condition may occur. If a new event is triggered while "console.log" is fetching the value related to the event, the newer value is wrongly returned to "console.log".
The following code snippet demonstrates this undesired behaviour;
// this is an example of how _NOT_ to manage state.
// do not replicate this.
module.exports = (NODE) => {
// stores the value when someevent is raised
let value;
// respond to the value output
NODE.getOutputByName('someoutput')
.on('trigger', async (conn, state) => {
return value;
});
// setup the event handler
NODE.on('trigger', (state) => {
someEventHandler.on('someevent', (event) => {
// save the value to its variable
value = event.value;
// trigger the 'trigger' output
NODE.getOutputByName('trigger')
.trigger(state);
});
});
});
Using state to store your values
To solve this, store your values in the state object that is passed between nodes. The below example does produce the result you would expect;
module.exports = (NODE) => {
// respond to the value output
NODE.getOutputByName('someoutput')
.on('trigger', async (conn, state) => {
const thisState = state.get(NODE);
return thisState.value;
});
// setup the event handler
NODE.on('trigger', (state) => {
someEventHandler.on('someevent', (event) => {
// save a value to the state chain
state.set(NODE, {value: event.value});
// trigger the 'trigger' output
NODE.getOutputByName('trigger')
.trigger(state);
});
});
});
If a certain value is idempotent, you can resort to simply storing the value in a local variable. Keep in mind that for "event" nodes this is hardly ever the case.