什么是React Hook?
一个特殊的函数,用于钩入React的特性。
它鼓励我们将通用逻辑封装成Hook而不是工具函数,明确了通用工具函数和业务工具函数的边界。
使用React Hook有些什么好处?
1:很好的解决了状态逻辑复用难的问题,避免了嵌套地狱的出现。
2:关注点分离,代码逻辑更为清晰。
3:避免了class不能很好优化的问题,如不能很好的压缩,热重载不稳定。
使用React Hook规则有哪些?
1:只能在顶层使用,目的是保证Hook在每一次渲染中都能按照相同的顺序被调用。
2:只能在函数组件或者自义定Hook中调用。
React Hook是如何与组件关联起来的?
react会保持对当前渲染组件的追踪,每一个组件内部都有一个记忆单元格,用于存储JS对象数据。当你调用Hook时就读取当前Hook所在组件的记忆单元格里面的数据。
有哪些React Hook?
下边我们来一一整理下这些Hook的用法以及每个Hook应该注意的隐藏问题!
1:useState
概述:
让函数组件也可以维护自己的state。
用法:
const [state, setState] = useState(initialState);
setState()可以直接传递一个newState, 也可以传递一个函数,可获取前一状态的值。
如:setState((prevState) => {})
注意:
useState()不同于setState(), 它是状态替换而不是状态合并。
建议:
将独立的Sate拆分开来,为什么?
原因一:useState的state是替换,不是合并,所以拆分开来比较合理。
原因二:有助于关注点分离,相关功能逻辑在一起,代码清晰易观。
2:useEffect
概述:
它具有与componentDidMount、componentDidUpdate、componentWillUnmount三个生命周期钩子相同的用途,它是他们三者合并后的API。
用法:
useEffect(() => {}, 可选数组参数)
1:第一个参数为函数,该函数内部执行的动作相当于componentDidUpdate和componentDidUpdate两个生命周期中要干的事情,其结果返回一个函数,该函数内部定义的动作相当于componentWillUnmount生命周期时要干的事情 。但值得注意的是这个返回函数并不是在组件销毁时候执行的,事实上它会在我们每次重新渲染后被调用。为什么?因为useEffect的执行机制,每次我们重新渲染的时候都会生成新的effect用来替换掉之前的effect。所以某种意义上来说, effect更像是渲染结果的一部分,每一个effect属于一次特定的渲染。
2:第二个参数为可选参数,可能的值为空数组或者是具体依赖数组。其作用是优化重新渲染性能,相当于我们生命周期中shouldComponentUpdate对触发更新的依赖对象进行浅比较然后来确定是否需要重新渲染更新。
2-1:当省略这个参数的时候,相当于setState后都要进行更新。
2-2:当为[]时,只初始化执行一次,后边不再进行更新。
2-3:当为具体的依赖对象数组时,具体的依赖对象有变化就更新重渲染,没变化就不更新重渲染。
3:useContext
概述:
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。
它其实相当于class组件中 static context = xxTheme。我理解为是获取环境变量值的钩子。
当使用了该钩子函数的组件最近一层的<MyContext.Provider>更新时,该钩子会触发重新渲染。即使祖先使用了React.memo或者ShouldComponentUpdate,也会触发重新渲染。
用法:
cons xxTheme = useContext(xxContext);
const xxContext = React.createContext("xxx");
4:useLayoutEffect
概述:
其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
尽可能使用标准的 useEffect 以避免阻塞视觉更新。
5:useRef
概述:
它不仅可以用于DOM refs。它还是一个current属性可变且可以容纳任意值的通用容器,类似于class的实例属性。
用法:
const myRef = useRef(initialValue);
6:useCallback
概述:
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
抽离useEffect中的公共逻辑时很有用。
用法:
useCallback(fn, deps)
7:useMemo
概述:
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。
你可以把 useMemo 作为性能优化的手段,但不要把它当成语义上的保证。将来,React 可能会选择“遗忘”以前的一些 memoized 值,并在下次渲染时重新计算它们,比如为离屏组件释放内存。先编写在没有 useMemo 的情况下也可以执行的代码 —— 之后再在你的代码中添加 useMemo,以达到优化性能的目的。
用法:
useMemo(() => fn, deps)
8:useReducer
概述:
它其实是一个内置的自定义Hook。
当你有个相当复杂的组件包含了大量以特殊方式来管理的内部状态,我们通常会使用redux三方库来进行管理。但是如果此时你并不想引入三方库,那么自定义钩子函数useReducer就会是一个很不错的选择。
用法:
const [state, dispatch] = useReducer(reducer, initialArg, init);
具体实现参考官网自定义Hook
注意:
所谓惰性初始化,就是将用于计算state的逻辑抽取到reducer外部,这对未来重置state的action很有便利。
9:useImperativeHandle
概述:
在使用ref时自义定暴露给父组件的实例值。
它应当和forwardRef一起使用。
用法:
useImperativeHandle(ref, handle, [deps])
10:useDebugValue
概述:
useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。
用法:
useDebugValue(value)
如: useDebugValue(isOnline ? "online" : "offline")
11: 自定义Hook
概述:
2个或更多组件间公用逻辑部分抽取封装成一个新的函数,函数名以use开始,内部可以调用其他Hook。
注意一:为什么要以use开头,这个约定主要是为了判断该函数内部是否使用了Hook调用,方便自动检查Hook调用是否符合规范。
注意二:两个或多个组件内部使用相同的自定义Hook不会共享state。自定义Hook只是一种重用状态逻辑的机制,从react的角度来看,我们的组件只是多次调用了useState和useEffect,它们是完全独立的。
网友评论