什么是Preact
Preact可以理解为体积更小的react,实现了react的大部分功能,源码相对于react比较简单。Preact也实现了react中的hooks的内容,所以本文从Preact中探索hooks的实现原理。
useState的使用
先来看下useState的简单使用,在这里我们借用官网的例子。
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
可以看到,函数组件里面也有了state,也可以通过setCount来改变count的值。
useState的原理
1.useState
在Preact中useState的代码如下
export function useState(initialState) {
return useReducer(invokeOrReturn, initialState);
}
useState接收一个参数initialState
,返回了一个函数userReducer
的返回值
2.userReducer
export function useReducer(reducer, initialState, init) {
// 定义了hookState,调用getHookState
const hookState = getHookState(currentIndex++);
if (!hookState._component) {
// 给hookState添加_component属性
hookState._component = currentComponent;
// 给hookState添加_value属性
hookState._value = [
// 对initialState做处理
!init ? invokeOrReturn(undefined, initialState) : init(initialState),
action => {
// 执行reducer,返回nextValue
const nextValue = reducer(hookState._value[0], action);
if (hookState._value[0] !== nextValue) {
// 如果hookState._value第一个参数等于nextValue,调用setState更新状态
hookState._value[0] = nextValue;
hookState._component.setState({});
}
}
];
}
return hookState._value;
}
userReducer的代码比较复杂,下面我们一一说明:
- 接收3个参数
reducer
、initialState
、init
- 定义了
hookState
,调用getHookState
- 给
hookState
添加_value
属性 - 处理
hookState
的_value
属性 - 返回了
hookState._value
在这里我们回想下useState的用法,const [count, setCount] = useState(0);
,
useState
可以接收一个初始值,返回一个count,这个count是根据初始值变化得来的,
另个一参数setCount
,接收一个参数,产生的作用是改变了count的值,并改变视图。
正好对应了上面的第4步: 处理hookState
的_value
属性
那么问题又来了,hookState
又是什么?
根据上面的代码const hookState = getHookState(currentIndex++);
,getHookState
函数接收一个参数currentIndex++
,返回值赋给hookState
,废话不多说,上代码!
3.getHookState
import { options } from 'preact';
function getHookState(index) {
// 瞅瞅Preact里面有没有_hook,从当前组件中拿到hook的state
if (options._hook) options._hook(currentComponent);
// 定义一个数组_list
const hooks =
currentComponent.__hooks ||
(currentComponent.__hooks = { _list: [], _pendingEffects: [] });
if (index >= hooks._list.length) {
hooks._list.push({});
}
// 返回这个数组index这一项
return hooks._list[index];
}
getHookState
做的是:定义一个数组,根据传来的值,返回匹配到的数组。由此,我们会想到什么呢,对就是这个,一图胜千言!