Hook 解决的问题
- state 共享重用(useState)
- class 中生命周期函数经常包含不相关的逻辑,但又把相关逻辑分离到了几个不同方法中的问题(useEffect)
副作用
在前端开发中,经常会听到副作用的这个说法,很多人以为和吃药有副作用是一个意思,其实不是,前端的主要作用就是 data 到 UI 的渲染,所以这里说的副作用就是除了 data 渲染成 UI 以为的其他操作都算是副作用。比如事件绑定,获取数据等等。
useState 是有顺序要求的,并且每次调用,需要调用所有声明过的 useState。
也就是说:调用时,必须按照已有的顺序和数量进行调用。 ###如何避免少调用了 useState
可以通过eslint-plugin-react-hooks
来帮助检验。
1 | npm i -D eslint-plugin-react-hooks |
在 package.json 中增加配置,在顶级增加如下:
1 | "eslintConfig": { |
这样有地方写的不符合规则,就会报错。
useState 使用函数初始化
有时候,我们需要根据条件去初始化 state,如果先计算好条件,然后在把结果传递给 useState,这样会使计算过程每次渲染都会执行,然而只有第一次初始化是需要用到这些条件判断的,以后的每次执行都是浪费,如下
1 | function App(props) { |
只有第一次从 props 中获取 defaultCount 是有用的,以后的每次渲染这样代码照样执行,但是是没有价值的。
可以给 useState 传递函数来初始化,函数的返回值就是默认值。
1 | function App(props) { |
每次 state 的改变 App 函数都会执行,react 是如何知道每次的调用是不是第一次?
useState 的内部机制做了处理。并且在 state 没发生改变的时候,是不会引起新的渲染的。
class 中的 setState 和 useState 更新 state 的区别
- class 组件中的 setState 是用更新的属性和原来的 state 进行合并,然后再更新。
1 | this.state = { |
当通过 setState 只更改 name 时,age 也不会丢失,react 会先用现在发生变化的 state 和原来的 state 进行合并,然后再更新。
- useState 更新 state 是替换原来的 state。
1 | const [person, setPerson] = useState({ name: "zhagnsan", age: 20 }); |
通过上面的更新,原来的 person 会被替换,age 属性丢失了。
ContextHook
我们可以通过 Consumer 获取 context 的值,但是每次声明 Consumer 很麻烦,所以有了静态的 contextType,但是 contextType 每个组件只能有一个,如果声明多个,最后一个有效。
使用 contexthook 可以轻松解决上面的问题。
1 | const count = useContext(CountContext); |
memoHook
useMemo
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 。
注意:只要是依赖项改变,就会重新计算。(有时候不要被设置的布尔值给迷惑了)
如果只需要 useMemo 计算一次,第二个参数传空数组即可。
useMemo 也可以用于返回一个函数,如果返回的是函数,则可以直接使用 useCallback.第二个参数如果是空数组,则 useCallback 则会只生成的一次函数,即使返回的是箭头函数,也不影响。
effect hook
React 将按照 effect 声明的顺序依次调用组件中的每一个 effect。
effect 每次调用都会用一个新的函数,生成一个新的 effect,所以每次调用之前都会清楚之前的。