昨天介实作一个阳春的 useState ,今天来换 useEffect 吧!透过实作来帮助我们以後在写这两个 hooks 的时候,能够更有画面!
先来看看我们前两天完成的 useState 的程序码
const hooks = [] // 使用阵列来收集每一次 hook 呼叫
let callId = 0 // 用来纪录每一次 hook 呼叫的顺序
function myUseState(initialValue) {
const id = callId++
if (hooks[id]) return hooks[id]
function setState(newValue) {
let nextValue
typeof newValue === 'function' ? nextValue = newValue(hooks[id][0]) : nextValue = newValue
if (hooks[id][0] === nextValue) return
hooks[id][0] = nextValue
callRender()
}
const stateArray = [initialValue, setState]
hooks[id] = stateArray
return stateArray
}
const Counter = () => {
//.....
}
function callRender() {
callId = 0
ReactDOM.render(<Counter />, document.getElementById('root'))
}
callRender()
我们在最外面设置了 hooks 阵列与 callId,来帮助我们纪录每一个 hook 被呼叫的顺序以及该纪录的值。所以我们就可以利用这点,来纪录 useEffect 中的 dependency array 。 为什麽要纪录呢?就让我们先来快速复习一下 useEffect 吧!
所以要完成第二点,我们就需要利用 hooks array 来纪录 dependency array,比对每一次 re-render 传进来的 dependencies 与纪录在 hooks 中的是不是都一样。
接下来我们就来尝试完成 myUseEffect 吧!
function myUseEffect(callback, depArray) {
callback()
hooks[callId] = depArray
callId++
}
function myUseEffect(callback, depArray) {
const prevDepArray = hooksp[callId]
callback()
hooks[callId] = depArray
callId++
}
function myUseEffect(callback, depArray) {
const prevDepArray = hooksp[callId]
let hasChange = true
if (prevDepArray) {
hasChange = depArray.some(
(dep, idx) => !Object.is(dep, prevDepArray[idx])
)
}
if (hasChange) callback()
hooks[callId] = depArray
callId++
}
function myUseEffect(callback, depArray) {
const prevDepArray = hooksp[callId]
let hasChange = true
if (prevDepArray) {
hasChange = depArray.some(
(dep, idx) => !Object.is(dep, prevDepArray[idx])
)
}
if (hasChange) {
setTimeout(() => {
callback()
}, 100)
}
hooks[callId] = depArray
callId++
}
这样子,我们就土炮完成了 myUseEffect 了!
接下来,来试试看它是不是能够运作,将 Counter 元件,加上 myUseEffect ,当 count 变化时,改变 document.title 。
const Counter = () => {
const [count, setCount] = myUseState(0)
const [count2, setCount2] = myUseState(10)
myUseEffect(() => {
console.log('只执行第一次')
}, [])
myUseEffect(() => {
document.title = `Click ${count} times`
}, [count])
myUseEffect(() => {
console.log('只执行第一次,除非改变 count2')
}, [count2])
const increaseHandler = () => {
setCount(prev => prev + 1)
}
const decreaseHandler = () => {
if (count === 0) return
setCount(prev => prev - 1)
}
return (
<div className="container">
<button className="minus" onClick={decreaseHandler}>-</button>
<span className="number">{count}</span>
<button className="plus" onClick={increaseHandler}>+</button>
</div>
)
};
顺利的话,就会看到当我们按下 count ,document.title 会如预期改变,另外两个 myUseEffect 都只会第一次执行。
以上就是今天的介绍,如果有任何问题都欢迎在下方留言,明天我们将在继续介绍其他的 hooks!
该文章同步发布於:我的部落格
<<: Day17 - [丰收款] 永丰API虚拟帐户付款与PayToken查询与更新状态
>>: Day 17: Structural patterns - Proxy
如果你有 Localhost 开发环境需要以 HTTPS 浏览时,可以参考以下方法: 方法一:vue...
Hello 大家, 今天第一个要讲的是拍摄萤幕快照, 嘿嘿~就是截图, 没啥好说的XD, 但截图後面...
前言 在处理 PDF 增加密码 (加密) 、移除解密 (解密) 时,可以使用 Ghostscript...
摘要 建立一个 container 集合体,包含两个 container, db 跟 wordpre...
身为一个普大的普通大学生, 实战经验少得可怜, 除了学过资工基本学科,就只会用 Python 写 L...