什么是hooks?
在function组件中,每一次更新都是一次新的函数执行,为了保存一些状态,执行一些副作用钩子,所以产生了hooks,去帮助记录组件的状态,处理一些额外的副作用。
hooks的内部运行机制
首先每次执行一个hooks函数,都产生一个hook对象,里面保存了当前hook信息,然后将每个hooks按照定义的顺序以链表形式串联起来,并存放到memoizedState中。更新的时候,再按照顺序,从 memoizedState 中把上次记录的值拿出来。
这样我们就可以解答几个问题:
Q:为什么只能在函数最外层调用 Hook?为什么不要在循环、条件判断或者子函数中调用。
A:memoizedState 数组是按 hook定义的顺序来放置数据的,如果 hook 顺序变化,memoizedState 并不会感知到。
Q:自定义的 Hook 是如何影响使用它的函数组件的?
A:共享同一个 memoizedState,共享同一个顺序
useState原理
相信大家对useState都有一定的了解(react中Hooks的基本用法),在这里只补充一点。
setState 的两种用法:
setState(value)
setState(prevCount => ++prevCount)
当我们更新state需要依赖之前的值时,我们可以在setState中接受一个函数来实现。
接下来我们简单地实现一个useState。
import { Button } from 'antd';
let state: any; // 把 state 存储在外面
const useState = (initialValue: any) => {
// 如果没有 state,说明是第一次执行,把 initialValue 复制给它
state = state | initialValue;
const setState = (newState: any) => {
state = newState;
}
return [state, setState];
}
export default function State() {
const [count, setCount] = useState(0);
return (
<div>
<div>{count}</div>
<Button
onClick={() => {
setCount(count + 1);
}}
>
点击
</Button>
</div>
);
}
useEffect
我们知道 useEffect 有几个特点:
• 有两个参数 callback 和 dependencies 数组
• 如果 dependencies 不存在,那么 callback 每次 render 都会执行
• 如果 dependencies 存在,只有当它发生了变化, callback 才会执行
我们再简单的实现一个useEffect:
// _deps 记录 useEffect 上一次的 依赖
let _deps: { [x: string]: any; };
function useEffect(callback: () => void, depArray: any[]) {
// 如果 dependencies 不存在
const hasNoDeps = !depArray;
// depArray未改变则为false
const hasChangedDeps = _deps
? !depArray.every((el, i) => el === _deps[i]) // 两次的 dependencies 是否完全相等
: true;
// 如果 dependencies 不存在,或者 dependencies 有变化
if (hasNoDeps || hasChangedDeps) {
callback();
_deps = depArray;
}
}
到这里我们又可以解决一个问题:
Q:为什么第二个参数是空数组,相当于 componentDidMount ?
A:因为依赖一直不变化,callback 不会二次执行。