Skip to content

6 Reacting to changes

jonathandewitt-dev edited this page Dec 17, 2021 · 6 revisions

Say we want to react to changes on a particular property in the state...

const state = new State({

  name: 'Demo',

  state: {
    firstName: 'Jon',
    lastName: 'DeWitt',
  },

  actions: {
    changeName({state, payload}) {
      state.firstName = payload.firstName
      state.lastName = payload.lastName
    },
  },

})

This can be accomplished via the watchers property. Each property on the state is also added to watchers as a function that takes a callback. This callback will run every time the corresponding property is updated in the state, feeding it the new value as the first argument, and an optional clean-up function as the second argument.

state.watchers.firstName((newFirstName, destroy) => {
  document.querySelector('#fname').textContent = newFirstName
  destroy() // removes this watcher so it will no longer react to changes
})

The same also applies to computed properties.

...

 computed: {
    fullName(state) {
      return `${state.firstName} ${state.lastName}`
    },
  },

...
state.watchers.fullName((newFullName, destroy) => {
  document.querySelector('#name').textContent = newFullName
  destroy() // removes this watcher so it will no longer react to changes
})

As of version 0.3.0, you are now able to destroy watchers from outside the callbacks as well. This is especially helpful in cases where you require cleanup, such as with React's useEffect hook. Each watcher function now has an extra property called destroy, which takes the callback to be removed as an argument.

const watchFullName = newFullName => {
  document.querySelector('#name').textContent = newFullName
}
state.watchers.fullName(watchFullName) // begins reacting to changes
state.watchers.fullName.destroy(watchFullName) // removes this watcher so it will no longer react to changes

Beware of a small caveat when doing this. Because actions are always asynchronous by nature, destroy is also asynchronous to avoid interfering with the event loop that's already been set in motion. To enable workarounds, destroy returns a promise so you may await or chain then methods.

Clone this wiki locally