弑
弑君者
V1
2022/04/13阅读:67主题:默认主题
手把手带你了解useState原理
useState 是什么?如何实现?
react hooks 已经出来很长时间了,相信很多人都使用过,比如useState,useEffect等。
但是我们有没有想过useState的原理是什么?假如让你实现useState,你会如何实现呢?
大家可以先思考些。
我一直相信一句话,假如你不能创造它,你就根本没有了解它!!!
useState的原理
useState的本质是什么?如果除去react相关的一些乱七八糟附加信息,那么useState的本质是什么呢?
说白了就是在一个函数app里边调用useState,比如第一次调用的时候,执行
const [num,updateNum] = useState(1);
得到num等于1
然后当调用updateNum的时候,比如如下调用的时候,收集依赖到数组arr中
updateNum((num)=>num+1);
执行完之后arr=[(num)=>num+1] 等到下次再执行app之后,这时候我们就会得到根据arr里边收集的依赖,得到新的num等于2.
所以useState的本质是什么呢?
就是一个可以保存状态,并且可以收集依赖,等到下次再执行的时候,根据依赖重新获取更新之后的状态的函数。
实现一个简单的useState
我们根据上面介绍,来实现一个简单的useState,把基本原理了解清楚,然后自己再去使用或者看源码,就会更清楚了。
我们采用自上而下的方法,先搭建好框架,然后再把需要的填进去就可以了。
function app() {
const [num,updateNum] = myUseState(1);
return {
updateNum
}
}
这里我们知道在执行myUseState的时候,是需要保存上一次执行之后的状态的,所以我们需要两个变量。
// 用来保存上一次状态
let fiber = {
};
// 区分是否调用过
let hasCalled = false;
然后逻辑就比较简单了,我们在第一次执行函数的时候,创建一个对象挂载到fiber上,然后返回一个数组,当函数执行过之后,我们只需要更新状态就可以了。
// 返回更新状态的函数,这里是挂载到全局fiber.hook.pending上
function dispatch(pending,action) {
pending.action=action;
}
function myUseState(initState) {
// 还没有执行过函数
if(!hasCalled) {
// 创建一个对象
const hook = {
basicState: initState,
pending: {
action:null
}
}
// 挂载到fiber上
fiber.hook = hook;
// 标记已经执行过
hasCalled=true;
// 返回一个数组
return [hook.basicState,dispatch.bind(null,fiber.hook.pending)]
}else {
// 当已经执行过该函数,只需要更新状态就可以了
fiber.hook.basicState = fiber.hook.pending.action(fiber.hook.basicState);
// 返回数组
return [fiber.hook.basicState,dispatch.bind(null,fiber.hook.pending)]
}
}
代码比较简单,完整的注释已经在代码里边了。
完整的代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function app() {
const [num,updateNum] = myUseState(1);
console.log(111,num)
return {
updateNum
}
}
// 用来保存上一次状态
let fiber = {
};
// 区分是否调用过
let hasCalled = false;
// 返回更新状态的函数,这里是挂载到全局fiber.hook.pending上
function dispatch(pending,action) {
pending.action=action;
}
function myUseState(initState) {
// 还没有执行过函数
if(!hasCalled) {
// 创建一个对象
const hook = {
basicState: initState,
pending: {
action:null
}
}
// 挂载到fiber上
fiber.hook = hook;
// 标记已经执行过
hasCalled=true;
// 返回一个数组
return [hook.basicState,dispatch.bind(null,fiber.hook.pending)]
}else {
// 当已经执行过该函数,只需要更新状态就可以了
fiber.hook.basicState = fiber.hook.pending.action(fiber.hook.basicState);
// 返回数组
return [fiber.hook.basicState,dispatch.bind(null,fiber.hook.pending)]
}
}
const myApp = app();
myApp.updateNum((num)=>num+1);
app()
</script>
</body>
</html>
执行结果如下:

作者介绍
弑
弑君者
V1