大家好,我是踩坑小星球。作为一个 Component 拥护者,迈出一小步踩下 Hook ,看看它到底是个啥玩意儿。
基础语法之类的就不说了,文章多的是,这个只是我自己在开发的时候,需要注意的点~
[TOC]
关于状态
useState
管理状态,这里有一点需要注意,当你使用 useState 的 set方法的时候,旧状态不会自动 merge到新状态中去,也就是 set 所改变的是全量数据。
这句话的意思就是,如果你的 state 是一个对象,你需要手动的构成一个完整的新数据
// 定义 const [obj,setObj] = useState({name: "小蘑菇",age: 0 }); // 更新 setObj({ ...obj, name: "大蘑菇" }); // 结果 // {name: "大蘑菇",age: 0 }
-
useState
产生的 state 作为函数中的一个常量,就是普通的数据,并不存在诸如数据绑定这样的操作来驱使 DOM 发生更新。在调用 setState 后,React 将重新执行 render 函数,仅此而已。因此,状态也是函数作用域下的普通变量。
我们可以说每次函数执行拥有独立的状态,具有 Capture Value 的特性,简单来说,就是它不能实时。 -
利用
useRef
就可以绕过 Capture Value 的特性。可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最终状态,而不会在每个 Render 间存在隔离。
原因是因为,ref.current 将被赋予初始值 initialValue,之后便不再发生变化。但你可以自己去设置它的值。设置它的值不会重新触发 render 函数。
function Example() { const [count, setCount] = useState(0); // Initial ref const latestCount = useRef(count); useEffect(() => { // Set the mutable latest value latestCount.current = count; setTimeout(() => { // Read the mutable latest value console.log(`You clicked ${latestCount.current} times`); }, 3000); }); // ... }
生命周期
Component 最大的好处是有生命周期可以处理各种数据,在 Hook 也可以利用Effect钩子
模拟这种生命周期
- 通常我们会利用组件的生命周期函数去执行一些副作用,但通常副作用逻辑复杂,可能会有 Bug,所以在 Hook 里,建议
针对每一段逻辑单独使用一个Effect钩子
useEffect(() => { console.log('模拟componentDidMount'); return () => { console.log('模拟componentWillUnmount') } }, []); useEffect(() => { console.log('模拟componentDidMount以及name改变时,模拟componentDidUpdate'); return () => { console.log('name改变时,都会先触发这里,再触发上面的effect') } }, [name]);
-
对于 useEffect 来说,执行的时机是完成所有的 DOM 变更并让浏览器渲染页面后,而 useLayoutEffect 和 class 组件中 componentDidMount, componentDidUpdate一致——在 React 完成 DOM 更新后马上同步调用,会阻塞页面渲染.
-
利用
useMemo
减少不必要的渲染
function Parent({ a, b }) { // Only re-rendered if `a` changes: const child1 = useMemo(() => <Child1 a={a} />, [a]); // Only re-rendered if `b` changes: const child2 = useMemo(() => <Child2 b={b} />, [b]); return ( <> {child1} {child2} </> ) }
注意事项
- 不要在循环,条件或嵌套函数中调用 Hook ,必须始终在 React 函数的顶层使用 Hook 。这是因为React需要利用调用顺序来正确更新相应的状态,以及调用相应的钩子函数。一旦在循环或条件分支语句中调用Hook,就容易导致调用顺序的不一致性,从而产生难以预料到的后果。
- 只能在 React 函数式组件或自定义 Hook 中使用 Hook
- 可以安装 eslint 插件
eslint-plugin-react-hooks
,在.eslintrc.js中加入配置
{ "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error" } }
- 谨慎将处于同个 useEffect dependences 之中且有逻辑关联的 state 放在多个 useEffect中