Skip to content

Using $state()

INFO

$state() is a method, used in the Template Tree.

$state() accepts a State as an input, and it calls the provided callback function once, so you can render some DOM elements, representing the state. The callback function provides one argument - the input state.

js
x.$state(myState, (myState) => {
  // ...
})

The reactivity happens when you change the state itself - then the rendered DOM elements are removed, the callback is called again and new DOM elements are rendered.

But how to change the state? If you have the state in a variable, and you set the variable to something else, the variable is simply reassigned:

js
import { state } from 'paintor'

let myState = state(['one'])

myState = ['two']
// At this point myState lost the reference to the state
// and points to the ['two'] array

One solution is to use a sub-state, because states are recursive:

js
import { state } from 'paintor'

const myStates = state({ subState: ['one'] })

myStates.subState = ['two']

And the other solution is to use setState():

js
import { setState, state } from 'paintor'

let myState = state(['one'])

setState(myState, ['two'])

Sub-State Example

js
import { compose, state, template } from 'paintor'

const MyComponent = function() {
  return template((x) => {
    const myStates = state({ subState: {} })
    const buttons = [
      { type: 'text', value: 'Text' },
      { type: 'password', value: '123456' },
      { type: 'range', value: '25' },
      { type: 'color', value: '#0000FF' }
    ]

    for (const button of buttons) {
      x.button({
        textContent: button.type,
        onClick: () => {
          myStates.subState = button
        }
      })
    }

    x.hr()

    x.$state(myStates.subState, (subState) => {
      x.input({
        type: subState.type,
        value: subState.value,
      })
    })
  })
}

compose(MyComponent()).paint('#using-state-1')
html
<div id="using-state-1"></div>
example

setState() Example

js
import { compose, setState, state, template } from 'paintor'

const MyComponent = function() {
  return template((x) => {
    const myStates = state({ subState: { type: 'text', value: 'Text' } })
    const buttons = [
      { type: 'text', value: 'Text' },
      { type: 'password', value: '123456' },
      { type: 'range', value: '25' },
      { type: 'color', value: '#0000FF' }
    ]

    for (const button of buttons) {
      x.button({
        textContent: button.type,
        onClick: () => {
          setState(myStates.subState, button)
        }
      })
    }

    x.hr()

    x.$state(myStates.subState, (subState) => {
      x.input({
        type: subState.type,
        value: subState.value,
      })
    })
  })
}

compose(MyComponent()).paint('#using-state-2')
html
<div id="using-state-2"></div>
example