Starting Part 2 and Part 3, useEffect
and useState
are detailed examined on all usages. In this Part 4 we’d like to reveal the generic feature of a Hook
.
Given a Hook
and a unique id
, for the first time it can be initialized via constructor
. For each element update, the hook
invokes update
with the args
.
class Hook {
constructor(id, element) {
this.id = id
this.el = element
}
}function hook(Hook, ...args) {
let id = notify()
let hook = hooks.get(id)
if(!hook) {
hook = new Hook(id, element, ...args)
hooks.set(id, hook)
}return hook.update(...args)
}
Constructor
// useEffect(() => {}, [])
const useEffect = hook(class extends Hook {
constructor(id, element) {
super(id, element)
element['effects'].push(this)
}
})// [value, setValue] = useState(0)
const useState = hook(class extends Hook {
constructor(id, element, initialValue) {
super(id, element)
this.array = [initialValue, this.updater]
}
})
For useEffect
, it registers the effect
to the effects
list. For useState
it initialize the array
.
Update
// useEffect(() => {}, [])
const useEffect = hook(class extends Hook {
update(callback, values) {
this.callback = callback
this.lastValues = this.values
this.values = values
}
})// [value, setValue] = useState(0)
const useState = hook(class extends Hook {
update() {
return this.array
}
})
The arguments args
are worth noting because it's passed in every render cycle.This is especially true for useEffect
. The callback
, and dependency values
are sent as a new copy by default as inputs. There's no returns from useEffect
.
TL;DR
A Hook is unique and defines its own behavior while implementing constructor
and update
. constructor
is called once during registration while update
is invoked in all element updates with arguments
passed in.
Index
- Part 1, Element
- Part 2, useEffect
- Part 3, useState
- Part 4, Hook <- YOU ARE HERE
- Part 5, Custom Hook
The code snippets used are heavily borrowed and simplified from the early draft of Repo Haunted
for lit-element
.