https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e
参考了这篇文章,对hooks的实现有初步的了解,具体的还是得研究一下官方的,这篇文章用了一个简单的方式和代码去介绍React的hooks是如何实现的。
平时我们经常使用的Hook是useState()
通过其的一个简单实例
function RenderFunctionComponent() {
const [firstName, setFirstName] = useState("Rudi");
const [lastName, setLastName] = useState("Yardley");
return (
<Button onClick={() => setFirstName("Fred")}>Fred</Button>
);
}
我们使用useState()通常的代码的,一般最好奇的事情就是,为什么是
const [key, setkey] = useState()
我们更新值的话都是通过
setKey(new value)
去更新的,所以这个时候就会很懵懂其背后是怎么实现更新的。
下面借鉴上述博客中的图去理解
(1)初始化
创建两个空的数组 state 和 setters, 同时讲指针设置为0
(2)第一次渲染
在第一次运行时,会将setter函数放入setters数组,同时会记录指针现在的位置,然后讲对应的state放入state数组。
(3)后面的渲染
初始化过后,指针会初始化到0,这样做是为了可以讲每个值从数据中读出
(4)请求的处理
每一个setter对游标位置都有一个引用,所以更改state的值就是通过去调用setter从而触发其对应数组在对应位置的值
在这里其实对setters函数的作用就有一点明白了,但是这里仅仅用于理解,背后的数据结构设计应该没那么简单。
最主要可以理解的点就是state的值是不断变化的,那么其就不能固定去寻找了(要做应该也行,可能在数据结构方面的开销会更大吧,不然如果可以用一个map解决开发团队绝不会用得那么麻烦),通过一个setter函数,首先名字是固定的,其实通过指针(游标)去确定对应的state值的位置,并将其更新。
通过一段简单的代码去理解
let state = [];
let setters = [];
let firstRun = true;
let cursor = 0;
function createSetter(cursor) {
return function setterWithCursor(newVal) {
state[cursor] = newVal;
};
}
// 模仿一个useState的函数
export function useState(initVal) {
if (firstRun) { // 判断是不是第一次渲染吧
state.push(initVal);
setters.push(createSetter(cursor));
firstRun = false;
}
const setter = setters[cursor];
const value = state[cursor];
cursor++;
return [value, setter];
}
// 使用hooks的组件代码
function RenderFunctionComponent() {
const [firstName, setFirstName] = useState("Rudi"); // cursor: 0
const [lastName, setLastName] = useState("Yardley"); // cursor: 1
return (
<div>
<Button onClick={() => setFirstName("Richard")}>Richard</Button>
<Button onClick={() => setFirstName("Fred")}>Fred</Button>
</div>
);
}
// 这是一种模拟的渲染周期
function MyComponent() {
cursor = 0; // resetting the cursor
return <RenderFunctionComponent />; // render
}
//下面就是不断执行代码,并得出相应的结果
console.log(state); // Pre-render: []
MyComponent();
console.log(state); // First-render: ['Rudi', 'Yardley']
MyComponent();
console.log(state); // Subsequent-render: ['Rudi', 'Yardley']
// click the 'Fred' button
console.log(state); // After-click: ['Fred', 'Yardley']
在这个模拟的过程中,不难发现,每次都是重新去变量setter和state的数组,虽然这个仅仅只是为了更好的理解,但是在渲染方面还是有点值得思路的,就是按道理应该每次重新渲染不是全部渲染,应该是局部的,这个感觉涉及到内部的匹配算法了。
但是通过上面,可以初步理解整一个过程其是大概怎么实现,同时在写代码的时候不会觉得很奇怪