Docs

Everything You Need to Know

Tutorials

State

More Than Just Data

ChocolateChip-UI's State object provides several things. First and foremost is encapsulation and abstraction. This allows us to isolate your data from accidental modification. It also enable's us to add capabilities for your data without having to register events, getters and setters or other intrusive operations. At the end of the day, the data you put in a ChocolateChip-UI state is clean and untouched. You can extract it from the state at any time.

// Data for state:
const person = {
  firstName: 'John',
  lastName: 'Doe',
  age: 32,
  job: 'developer'
}

// Define state:
const personState = new State(person)

Models expose a lot of useful methods to handle your data. You can find out about them in the section about Model API. Since the state we create above holds an object, we can use any of the state's object methods on it to change the data. But first lets create a component that we can bind to this object:

// Define a component:
const personComponent = new Component({
  element: '#person',
  render: (person) => html`
    <li id='person'>
      <div>
        <h3>${ person.firstName } ${ person.lastName }</h3>
        <h4>${ person.age }</h4>
        </p>${ person.job }</p>
      </div>
    </li>`
  // Bind component to state:
  state: personState
})
personComponent.render()

Because we've bound the component to the person State object, when we render the component, it does so with the data from the state. From now on, when we make any changes to the state, when we render the component, it will automatically get the latest version of the data.

When state holds an object, we have object related methods that we can use. For example, we can query a property on the state with getProp. So, with the above State object, we can get the firstName doing:

const firstName = personComponent.getProp('firstName')

Getting a property does not change a State object, and so there will be no change in its bound component. But if we change a property, it will:

personComponent.setProp('firstName', 'Tom')

By changing the property on our state, we cause the state to notify its subscriber, which in turn re-renders the component with the first name "Tom". Besides updating a property value of the state, we could add a new property using the same method. This would also trigger a re-render of the component. Note that if the property is not in the template, it won't get output. That said, it is possible to update a component's template to accomodate changing data needs.

You can also delete a state's property. Say, we want to delete the age property. We can do the following:

personComponent.remove('age')

Collections

Not all state hold objects. In fact, most state will hold arrays of objects. When you create a state from an array, you have a whole range of methods to access the objects in the array. When you bind a array state to a component, the component renders its template for each object in the array.

Earlier we made a person object. Now we're going to make an array of person objects and turn it into state:

const people = [
  {
    firstName: 'John',
    lastName: 'Doe',
    age: 32,
    job: 'developer'
  },
  {
    firstName: 'Sam',
    lastName: 'Smith',
    age: 28,
    job: 'mechanic'
  },
  // etc.
]

// Make a collection state:
const peopleState = new State(people, 'people-handle')

// Bind peopleState to this person component:
const personComponent = new Component({
  element: '#person',
  // Bind component to state:
  state: peopleState,
  render: (person) => html`
    <li id='person'>
      <div>
        <h3>${ person.firstName } ${ person.lastName }</h3>
        <h4>${ person.age }</h4>
        </p>${ person.job }</p>
      </div>
    </li>`
})
personComponent.render()

This will result in a list of two persons being rendered by the component. Now if we modify the state, the list will update automatically. Collection state support the same types of methods as arrays: push, pop, unshift, shift, sort, reverse, etc. Any of the methods that modify the state will alert the component's dispatch receiver that it has changed. And the receiver will then update the component. If we push or pop an item to the state, the list will update without us having to write any DOM manipulation code.

// Push another person object:
peopleState.push({
  firstName: 'Sally',
  lastName: 'Daniels',
  age: 27,
  job: 'entrepreneur'
})
// The component bound to peopleState
// will automatically update.

When Not To Use

Just because you can put data in a state doesn't mean you should. If your data is of a temporary nature, or is extremely simple, don't bother putting it in a state. If you need to perform multiple operations on the data in rapid succession, leave it raw JavaScript. You'll get better performance. However, there may be times where the array state methods make it trivial for you to accomplish complex tasks. In that case, use a state.

To learn more about state collection methods, please consult the documentation.