Simple reactivity system with composition API.
Hooks API has mental burden and unsolvable defects, this library can solve the following problems:
- Heavy state and repeated initialization.
In hooks API, Hooks will be initialized repeatedly. If there is a complex state, rendering will be blocked.
const [complexState] = useState(heavyData) // blocked
In Composition API, every component return a render function, this function will be rerendered every time, and state is initialized only once.
const data = reactive({ count: 0 }) // once
return () => vdom // every time
npm i doux -S
import { setup, reactive } from 'doux'
import { render } from 'react-dom'
const App = setup(() => {
const data = reactive({ count: 0 })
return () => (
<div>
<div>{data.count}</div>
<button onClick={() => data.count++}>+</button>
</div>
)
})
render(<App />, document.getElementById('root'))
Like memo or lazy, it receive a different composition compoent and return a new component
const App = setup(() => {
return () => (
<div>
<div>{data.count}</div>
<button onClick={() => data.count++}>+</button>
</div>
)
})
the composition component is different from hooks component, it return a pure render function, return () => vdom
Because closures, and from the second time on, the component will only reexecute this function.
This can solve the problem of repeated initialization rendering of hooks API.
Also you can receive a pure funtion without any logics:
const store = reactive({
count: 0
})
const App = setup(() => (
<div>
<div>{store.count}</div>
<button onClick={() => store.count++}>+</button>
</div>
))
For the closures, the reactive must nn parent scope.
It reversed a object and return a proxy object
const data = reactive({ count: 0 })
console.log(data.count) // 0
data.count++
console.log(data.count) //1
It accepts an effect function and run it when data changed.
const data = reactive({ count: 0 })
watch(() => console.log(data.count))
data.count++ // console 1
It will return a cleanup callback, you can use it to cleanup effects.
const cleanup = watch()
cleanup(()=> do()) // run both unmount and before update
In some cases, we may also want to watch with sources
// getter
const state = reactive({ count: 0 })
watch(() => state.count, (count, prevCount) => do())
// ref
const count = ref(0)
watch(count, (count, prevCount) => do())
Finally you can cleanup watcher
ref is another type of reactive, it just return an value
const ref = ref(0)
console.log(ref.value) //0
effect for reactive data, when deps changed, it will return a ref
const data = reactive({ count: 0 })
const double = computed(() => data.count * 2)
data.count++
Noneed lifecycles, use watch like useeffect:
watch | useEffect |
---|---|
watch(f) | useEffect(f) |
watch([x],f) | useEffect(f,[x]) |
setup | useEffect(f,[]) |
cleanup = watch() | useEffect(() => cleanup,[]) |
MIT ©yisar inspired by vue-next