State Management
States are some internal values maintained by an element.
These are important because if these values change, the element gets re-rendered.
You can refer to them in code, like in innerHTML, css or any other property of the element. On change, the element automatically updates their reference in the code.
$state Method
In SpuckJs, we use the state using $state method.
$statemethod returns a function to update that state.
NOTE: State can only be managed in a rendered element.
Let's see how it works.
/*
Lets create a new display element.
Render it while initializing because
State can only be managed in a rendered element.
*/
const Display = new Spuck({ type: 'h3', parent: '#app', id: 'dis' }).render();
const setCount = Display.$state('count', 0);
First Parameter: name of state
Second Parameter: initial value of state
Now to refer this state in the code, there are two ways:
.getState method
When you refer to the state value using this method, it will not update the reference in the code when state changes.It can only update if the line of code where this method is mentioned runs again.
That is, if used in a loop, bind to an event or used in an effect.
In all these cases, the state value will be updated when the line of code runs again.
$- reference
If you truly want to see the state reference update in the code, you use $- reference.
Syntax:
$-stateName
NOTE: $- can only be used in internal properties of the element. You can't do operations using this, { text: '$-count + 1' }.
Back to the example.
we are done withDisplay element, so we make it. We'll update the count using another element : Button
setState function
If you want to update any state of the element, you use the method returned by $state method.
By convention, we call this method set{StateName}
When you call it, it automatically re-renders the element after updating the state.
We pass a new value of state to this method.
There can be two ways for it:
Direct
Functional
Direct way
In this case, we pass the latest state value directly as parameter.
// suppose we want to update color of the element
setState('red');
// suppose we want to increment any "Click State" by 1
setClick(Element.getState('click') + 1);
// see how we "used" the "getState" method
Functional way
Here, we pass state value with respect to the previous state value as parameter using a functional approach
We call a function as parameter, whose argument is the previous state value.
Then we return a new value for state by manipulating previous one.
// suppose we want to update the state to double the previous value
setState(function(previousState) {
return previousState * 2;
});
// this can be simplified using arrow function
setState(prevState => prevState * 2);
// see how we "ignored" the "getState" method
⠀
Back to our Display example, we can use setState to update count on a button click
/*
Defining a button, we don't necessarily need to render
it at this point cause there is no state of the "Button"
to manage.
*/
const Button = new Spuck({ type: 'button', parent: '#app', id: 'btn' });
Button.prop = { text: 'Update Count' };
Button.events = {
// on click, update count using functional approach
click: () => setCount(prevCount => prevCount + 1)
};
Button.make();
Display at once:
const Display = new Spuck({ type: 'h3', parent: '#app', id: 'dis' }).render();
const setCount = Display.$state('count', 0);
Display.prop = { text: 'Count is $-count' };
Display.make('re');
const Button = new Spuck({ type: 'button', parent: '#app', id: 'btn' });
Button.prop = { text: 'Update Count' };
Button.events = {
click: () => setCount(prevCount => prevCount + 1)
};
Button.make();
State Sharing
In SpuckJs you can easily share states to other elements.
You can share states to siblings, parent, children or any other elements, it does not matter.
Pseudo Children/States
SpuckJs does it by using a concept called pseudo-Children.
If you want to share state of Element 1 with Element 2, you can do it by making "Element 2" a pseudo-Child of "Element 1".
const Element1 = new Spuck({ ... }).render();
const Element2 = new Spuck({ ... }).render();
Element1.init.pseudoChildren = [Element2];
Element1.render('re');
pseudoChildren is a property of init object of the element.It is an array, and can hold multiple elements.
Now all the states of Element 1 are accessible to Element 2 as pseudo-states.
NOTE: When an element renders, all its pseudo-children are also rendered.
Referencing them
Just like normal states, you can refer to pseudo-states either using:
.getPseudoStatemethod, or
$$-reference
NOTE: $-: states and $$-: pseudo-states
Extending "Display" Example
Suppose there is one more element, say Display2, below the Button, which shows the count of the Display element.
We will make Display2 a pseudo-child of Display, to access the count state.
const Display2 = new Spuck({ type: 'h3', parent: '#app', id: 'dis2' });
Display1.init.pseudoChildren = [Display2];
Display1.render('re');
count state of Display from Display2 as pseudo-state.
Looking at the Object
If we console log the Display element now, we can see how are properties managed.

You can see states are stored in _state property of the element.
Each state is an array => [value, setter]
Display : pseudo-child : Display2
It contains the whole virtual element of Display2 in the pseudoChildren array.
⠀
Looking at Display2

It does not differ much, but instead of _state property, its _pseudoState property is defined, which has the same structure as _state.
You can see the el property of both elements, that is the physical element stored within the virtual element.
If we console log Display.el, we can see the HTML element:

Its there if you ever have to interact with the browser api, you can use it.