Toc
0 results found
bbcfive
react hooks的基本实现

一、useState
自定义一个立即执行函数:ReactX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const ReactX = (() => {
let state;

const useState = (initialValue) => {
if (state == undefined) {
state = initialValue;
}

const setterFunction = (newValue) => {
state = newValue;
}

return [state, setterFunction];
};

return {
useState,
}
})();

使用useState:

1
2
3
4
5
6
7
8
9
10
11
12
13
const Component = () => {
const [counterValue, setCounterValue] = useState(1);

console.log(counterValue);

if (counterValue !== 2) {
setCounterValue(2);
}

};

Component(); // 1
Component(); // 2

二、升级useState
真实的state是array的形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let hooks = [];

let index = 0;
const useState = (initialValue) => {
const localIndex = index;
index++;

if (hooks[localIndex] == undefined) {
hooks[localIndex] = initialValue;
}

const setterFunction = (newValue) => {
hooks[localIndex] = newValue;
}

return [hooks[localIndex], setterFunction];
};

此时运行:

1
2
Component(); // 1
Component(); // 1

结果变成:
image.png
会发现值没有更新,因此需要一个新的resetIndex函数:

1
2
3
const resetIndex = () => {
index = 0;
}

然后再次使用即可得到预期结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const { useState, useEffect, resetIndex } = ReactX;

const Component = () => {
const [counterValue, setCounterValue] = useState(1);

if (counterValue !== 2) {
setCounterValue(2);
}

console.log('counterValue', counterValue);

};

Component(); // 1
resetIndex();
Component(); // 2

此时hooks的arr里只有一个值,即为最新值:
image.png
三、useEffect
useEffect需要根据传入的依赖是否改变而判断是否需要更新值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const useEffect = (callback, dependencyArray) => {
let hasChanged = true;

const oldDependencies = hooks[index];

if (oldDependencies) {
hasChanged = false;

dependencyArray.forEach((dependency, index) => {
const oldDependency = oldDependencies[index];
const areTheSame = Object.is(dependency, oldDependency);
if (!areTheSame) {
hasChanged = true;
}
});
}

if (hasChanged) {
callback();
}

hooks[index] = dependencyArray;
index++;
}

使用useEffect同样需要需要resetIndex,否则useEffect的callback函数会重复被调用:

1
2
3
4
5
6
7
8
9
10
11
const { useEffect, resetIndex } = ReactX;

const Component = () => {
useEffect(() => {
console.log("useEffect");
}, []);
};

Component();
resetIndex();
Component();

结果:
image.png
源码:https://github.com/bbcfive/react-hooks-demo/blob/main/ReactX.js
参考视频:https://www.youtube.com/watch?v=1VVfMVQabx0

本文作者:bbcfive
版权声明:本文首发于bbcfive的博客,转载请注明出处!