State Values

The concept of state is related to dynamic values, and it is an additional way to work with template values that you expect to change and that the template should react to.

const [count, setCount] = state(0);

const countUp = () => {
  setCount(prev => prev + 1)
}

const counter = html`
  <p>${count}</p>
  <button type="button" onclick="${countUp}">+</button>
`;

counter.render(document.body)

state

State is a core API much like html and unlike any state concept you might have heard of out there. It is part of the template system rather than some specific utility to manage state.

You create a state by calling the state function and providing it with an initial value.

state(0);

You can also provide an optional StateSubscriber as second argument if you want to react to the state update to perform some side effects for example.

state<number>(0, () => {
  // perform something after this state changes
});

The state call returns an array of 3 functions:

  • StateGetter: a function (dynamic value) that returns the latest value
  • StateSetter: a function to update the value that can be called with the new value, or a function that takes the current value and returns a new one.
  • StateUnSubscriber: a function to unsubscribe from the state if you provided a StateSubscriber to the state call.
const [count, setCount, unsubscribeFromCount] = state(0, () => {
  // perform something after this state changes
});

As mentioned, StateSetter can either take a new value, or a callback that gets called with current value and must return an updated one.

setCount(count() + 1)
setCount(prev => prev + 1)

How does state works?

The state is simply an observable the html template can subscribe to. This means that the template will know exactly what state changed and where in the template that state was used to update exactly the part of the DOM that depends on that data.

It provides an optimal way to react to dynamic value changes in comparison to the update function.

You can choose to render the state only once or keep it live, all depending on how you render it.

const [count, setCount] = state(0);

html`
  <!-- Will render once and not react to changes -->
  ${() => count()}
  ${count()}
  
  <!-- Will render and react to changes -->
  ${count}
  ${someHelper(count)}
`

To keep the state live, just “pass” it to the template as value or to a helper that takes StateGetter as argument. By default, all Markup helpers take StateGetter as argument.

effect

The effect helper was introduced for cases where you have places in the template that depends on a specific state, but you are doing some side effect calculation with that state.

const counter = html`
  <p>${count}</p>
  <p>${effect(count, () => count() * 2)}</p>
`;

Simply wrap a state or dynamic value in effect and comma separate all the states it depends on before your "side effect".

effect(...STATE, SIDE_EFFECT_ACTION_OR_STATE)

The effect is simply a type of Helper and you can learn more about helpers in the next section.