hooks在内存中是用链表进行存储的。
第一次渲染的时候,遍历组件,将各个hooks通过索引号index存储
再次渲染的时候,再次遍历,直接从索引号index里拿出既可
这也是为什么hooks不能写在if或循环语句中的原因
1.useState
let hookStates=[]//用于存储hooks的数组
let stateIndex=0 //用于指向hooks的索引号index
function useState(initState){
hookStates[stateIndex]=hookStates[stateIndex] || initState//第一次渲染(执行到useState)值为initState,再次渲染(执行到useState)值从数组中拿
let currentIndex=stateIndex//通过闭包把当前index保存下来,不然的话执行setState的时候index不是当前值(已经加了很多次了)
function setState(val){
hookStates[currentIndex]=val//替换对应位置的值,也就是更改对应位置hookstate中保存的值
render()
}
return [hookStates[stateIndex++],setState]
}
const root = ReactDOM.createRoot(document.getElementById('root'));
function render(){
stateIndex=0//每次渲染index都是从0开始的
root.render(<App />)
}
//const [count, setCount] = useState(1)
2.useMemo
function useMemo(callback,dependences){
if(hookStates[stateIndex]){//再次渲染(执行到useMemo)
let [lastMemo,lastDependences] = hookStates[stateIndex]//比较依赖项是否发生改变。如果没有直接返回lastMemo即可,如果改变了,就要生成新的对象
let same = dependences.every((item,index)=>{return item === lastDependences[index]})
if(same) {
stateIndex++;
return lastMemo;
}
else {
hookStates[stateIndex++]=[callback(),dependences]
return callback()
}
}
else{//第一次渲染(执行到useMemo)
hookStates[stateIndex++]=[callback(),dependences]//第一次是将回调的值和依赖项存进数组中
return callback()
}
}
3.useCallback
和usememo一样,只不过usememo缓存的是值,usecallback缓存的是函数
function useCallback(callback,dependences){
if(hookStates[stateIndex]){//再次渲染(执行到useMemo)
let [lastCallback,lastDependences] = hookStates[stateIndex]//比较依赖项是否发生改变。如果没有直接返回lastMemo即可,如果改变了,就要生成新的对象
let same = dependences.every((item,index)=>{return item === lastDependences[index]})
if(same) {
stateIndex++;
return lastCallback;
}
else {
hookStates[stateIndex++]=[callback,dependences]
return callback
}
}
else{//第一次渲染(执行到useMemo)
hookStates[stateIndex++]=[callback,dependences]//第一次是将回调的值和依赖项存进数组中
return callback
}
}
4.useEffect
useEffect解决函数式组件中,绑定事件、操作dom、定时器等一系列副作用
function useEffect(callback,dependences){
if(hookStates[stateIndex]){//再次渲染(执行到useEffect)
let [lastDestory,lastDependences] = hookStates[stateIndex]
if(lastDependences.length){//如果有依赖项
let same = dependences.every((item,index)=>item===lastDependences[index])
if(same){//如果依赖项没变,直接跳过
stateIndex++
}
else {//如果依赖项改变了,再更新
lastDestory && lastDestory() //如果有销毁函数则执行
hookStates[stateIndex++]=[callback(),dependences]
}
}else{//如果依赖项为空,直接跳过
stateIndex++
}
}
else{//第一次渲染(执行到useEffect)
hookStates[stateIndex++]=[callback(),dependences]//保存销毁函数(callback中的return函数)和依赖项
}
}
5.useReducer
和useState非常相似
function useReducer(reducer,initState){
hookStates[stateIndex] = hookStates[stateIndex] || initState
let currentIndex = stateIndex
function dispatch(action){
hookStates[currentIndex] =reducer(hookStates[currentIndex],action)
render()
}
return [hookStates[stateIndex++],dispatch]
}