watch-state
CANT inc. state management system.
This is a fast, tiny and smart state management system. Based on simplest principles: you have a state and you can watch for the state changes. Was born during working on innet.
watch-state inspired by async-await pattern, you can image it like this:
state count = 0
watch {
console.log(count)
}
Browser supports
Desktop
|
|
|
|
|
---|---|---|---|---|
45+ | 49+ | 9+ | 36+ | 13+ |
Mobile
|
|
|
|
---|---|---|---|
87+ | 90+ | 9+ | 62+ |
You can transpile it supporting old browsers, but the performance decreases.
Install
npm
npm i watch-state
yarn
yarn add watch-state
Or you can include this script to the head.
<script defer src="https://unpkg.com/watch-state/watch-state.min.js"></script>
Use watchState
to get any class from the library.
const {
Watch,
State,
Cache,
Event
} = watchState
Usage
Simple example:
You can create an instance of State
and watch it's value.
import { Watch, State } from 'watch-state'
const count = new State(0)
new Watch(() => console.log(count.value))
// console.log(0)
count.value++
// console.log(1)
count.value++
// console.log(2)
Update argument:
You can check if the watching ran first by update
argument.
const count = new State(0)
new Watch(update => {
console.log(update, count.value)
})
// console.log(false, 0)
count.value++
// console.log(true, 1)
count.value++
// console.log(true, 2)
As example, you can watch a state once
const count = new State(0)
new Watch(update => {
if (!update) {
// Watch this value
count.value
} else {
// React on changes
console.log('The value was changed')
}
})
count.value++
// console.log('The value was changed')
count.value++
// nothing happenes
Force update of State
You can run watchers of a state with update
method.
const count = new State(0)
new Watch(() => {
console.log(count.value)
})
// console.log(0)
count.update()
// console.log(0)
Force update of Watch
You can run a watcher even when it's states are not updated.
const count = new State(0)
const watcher = new Watch(() => {
console.log(count.value)
})
// console.log(0)
watcher.update()
// console.log(0)
destroy
You can stop watching by destroy
method of Watch
.
const count = new State(0)
const watcher = new Watch(() => {
console.log(count.value)
})
// console.log(0)
count.value++
// console.log(1)
watcher.destroy()
count.value++
// nothing happens
onDestroy()
You can subscribe on destroy or update of watcher
const count = new State(0)
const watcher = new Watch(() => {
console.log('count', count.value)
// the order does not matter
onDestroy(() => console.log('destructor'))
})
// console.log('count', 0)
count.value++
// console.log('destructor')
// console.log('count', 1)
watcher.destroy()
// console.log('destructor')
watcher.destroy()
count.value++
// nothing happens
Deep watch:
You can use Watch
inside a watcher.
Each watcher reacts on that states which used only inside it.
const watching = new State(true)
const state = new State(0)
let test = 0
new Watch(() => {
test++
if (watching.value) {
new Watch(() => {
console.log(state.value)
})
}
})
// console.log(0), test = 1
state.value++
// console.log(1), test = 1
watching.value = false
// test = 2
state.value++
// nothing happens
Cache:
You can cache computed state.
The watcher will not be triggered while new result is the same.
const name = new State('Foo')
const surname = new State('Bar')
const fullName = new Cache(() => (
`${name.value} ${surname.value[0]}`
))
new Watch(() => {
console.log(fullName.value)
})
// console.log('Foo B')
surname.value = 'Baz'
// nothing happens
surname.value = 'Quux'
// console.log('Foo Q')
You can force update the cache by update
method.
fullName.update()
// console.log('Foo Q')
Cache will be immediately updated only if a watcher looks after the cache.
You can use destroy
and onDestroy
like you do it on a watcher.
fullName.destroy()
The computing will be triggered only when a state inside the cache will be changed. So you can modify data only when it's needed.
const list = new State(['foo', 'bar', 'baz'])
const sortedList = new Cache(() => {
console.log('computing')
return [...list.value].sort()
})
// nothing happens
const value = sortedList.value
// console.log('computing')
console.log(sortedList.value)
// console.log(['bar', 'baz', 'foo'])
console.log(value === sortedList.value)
// console.log(true)
list.value = ['b', 'c', 'a']
// nothing happens
console.log(sortedList.value)
// console.log('computing')
// console.log(['a', 'b', 'c'])
Event:
Use Event
when you change several states to run their watchers after the event finished.
const name = new State('Foo')
const surname = new State('Bar')
const event = new Event()
new Watch(() => {
console.log(name.value, surname.value)
})
// console.log('Foo', 'Bar')
event.start()
name.value = 'Baz'
surname.value = 'Boo'
event.end()
// console.log('Baz', 'Boo')
You can use an event inside a watcher when you do not want to react on states
const count = new State(0)
const event = new Event()
new Watch(() => {
event.start()
console.log(count.value++)
event.end()
})
You will get loop without event
You can use globalEvent
every time if you do not want to extend the Event functionality.
import { State, globalEvent } from 'watch-state'
const count = new State(0)
new Watch(() => {
globalEvent.start()
console.log(count.value++)
globalEvent.end()
})
createEvent
You can create event function with createEvent
import { State, createEvent } from 'watch-state'
const count = new State(0)
const increase = createEvent(() => {
console.log(count.value++)
})
new Watch(increase)
Typescript:
Generic of State
const key = new State<string | number>()
key.value = false
// error, you can use only streng or number
Generic of Cache
new Cache<string>(() => false)
// error, target of cache should return string
Performance
You can check the performance test with MobX, Effector, Storeon, Mazzard and Redux. Clone the repo, install packages and run this command
npm run speed
Links
You can find more tools here
Issues
If you find a bug or have a suggestion, please file an issue on GitHub