React Hook | 必 学 的 9 个 钩子
React Hook 指南
什么是 Hook ?
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
Hook
本质上就是一个函数,它简洁了组件,有自己的状态管理,生命周期管理,状态共享。
useState
useEffect
useContext
useReducer
Hook 出现解决了什么 ?
组件之间状态复用, 例如:使用 useContext 可以很好的解决状态复用问题,或者自定义
Hook
来定制符合自己业务场景遇到的状态管理。在函数组件中 生命周期的使用,更好的设计封装组件。在函数组件中是不能直接使用生命周期的,通过
Hook
很好的解决了此问题。函数组件与 class 组件的差异,还要区分两种组件的使用场景。 使用
Hook
完全不用去想这些,它可以使用更多React
新特性。
什么时候使用 Hook ?
在函数组件顶层调用
在 函数中使用 / 自定义
Hook
中使用
React
内置的 Hook
useState
状态管理
useEffect
生命周期管理
useContext
共享状态数据
useMemo
缓存值
useRef
获取 Dom 操作
useCallback
缓存函数
useReducer
redux 相似
useImperativeHandle
子组件暴露值/方法
useLayoutEffect
完成副作用操作,会阻塞浏览器绘制
useState
状态管理
在
class
组件中,我们获取state
是 通过this.state
来获取的。而在
函数组件
中, 是没有this
的, 我们可以使用Hook
提供的useState
来管理和维护state
.
useState
定义 / 使用
const [state, setState] = useState(initialState)
setState 为更新 satate 方法
useState(initialState) initialState 为初始值
完整栗子
useEffect
生命周期管理
定义
useEffect
可以看作是函数式 组件
的 生命周期管理。因为在 函数式组件中无法直接使用生命周期,就必须托管
Hook
来进行管理使用了。
useEffect
可以使用的 3 个生命周期函数:
componentDidmount
componentDidUpdate
componentWillUnmount
无需清除Effect
使用
什么是无需清除
Effect
使用?React 更新 DOM 之后运行一些额外的代码
那么它就是在生命周期的
compoentDidmount
和componentUpdate
中执行即可。
清除Effect
使用
1. 什么是 清除
Effect
?当组件进行卸载时,需要执行某些事件处理时,就需要用到 class 组件生命周期的
componentUnmount
.在
useEffect
中很方便使用,在内部返回一个方法即可,在方法中写相应业务逻辑2. 为什么 要在
Effect
中返回一个函数 ?这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。
监听 state
变化
可以通过控制 监听
state
变化来实现相应的业务逻辑。
完整栗子
useRef
什么是 useRef
?
useRef
返回的是一个可变的 ref 对象,它的属性 current 被初始化为传入的参数(initialValue),返回的 ref 对象在组件的整个生命周期内保持不变。作用:
获取 Dom 操作,例如 获取
input
焦点获取子组件的实例(只有类组件可用)
在函数组件中的一个全局变量,不会因为重复 render 重复申明
栗子
useContext
状态数据共享
Context
解决了什么
在日常开发中,我们父子组件都是通过
props
来进行通信,如果遇到跨级组件通信
那么我们就不好通过props
来处理了。这时候可以想想怎么可以把 组件 状态 共享出去使用?
Context
Redux
.....
本小节通过
Context
来 达到组件数据共享
什么是 Context
数据共享,任何组件都可访问 Context 数据。
在
React
中,组件数据通过prop
来达到 自上而下的传递数据,要想实现全局传递数据,那么可以使用Context
.注意:
Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。
创建 Context
在使用
Context
前提,必须创建它,可以为它单独创建一个文件来管理Context
,
使用 Context
在使用
Context
时,它通常用在顶级组件(父组件上),它包裹的内部组件都可以享受到state
的使用和修改。通过
Context.Provider
来进行包裹,值通过value = {}
传递。子组件如何使用
Context
传递过来的值 ?
通过
useContext()
Hook 可以很方便的拿到对应的值.
useMemo
提升性能优化
定义
useMemo
用于性能优化,通过记忆值来避免在每个渲染上执⾏高开销的计算。
useMemo
参数:
useMemo
返回值是memoized
值,具有缓存作用
array
控制useMemo
重新执⾏的数组,array 中 的 state 改变时
才会 重新执行useMemo
注意:
不传数组,每次更新都会重新计算
空数组,只会计算一次
依赖对应的值,当对应的值发生变化时,才会重新计算(可以依赖另外一个 useMemo 返回的值)
栗子
解析栗子
当点击了 5 次更新
num
值,页面中newValue
的值始终显示为 0,这是为什么呢?因为我在
useMemo
监听记录的是count
的值,当count
值发生变化时,页面上的newValue
在会重新计算,虽然你点击了 5 次 更新num
,页面没有更新,但是已经缓存起来了,当点击 更新count
时,它会 计算count+1 的值 和 num 缓存的值
, 最终结果 为 5。减少了计算消耗。
useCallback
提升性能优化
定义
useCallback
可以说是useMemo
的语法糖,能用useCallback
实现的,都可以使用useMemo
, 常用于 react 的性能优化。
useCallback
的参数:
callback
是一个函数用于处理逻辑
array
控制useCallback
重新执⾏的数组,array改变时
才会重新执⾏useCallback
使用
它的使用和
useMemo
是一样的,只是useCallback
返回的函数。
小结
useMemo
和useCallback
功能类似,都是提升性能优化。该采用哪种方式来最佳实践,还有待探索。
欢迎 读者 与 我交流。
网上对
useMemo
和useCallback
的看法 ?
useCallback
如果在函数式组件中的话,确实应该当作最佳实践来用,但是使用它的目的除了要缓存依赖未改变的回调函数之外(与 useMemo 类似),还有一点是为了能够在依赖发生变更时,能够确保回调函数始终是最新的实例,从而不会引发一些意料之外的问题,我感觉后者才是使用 useCallback 的出发点,而非缓存。因为你想啊,即使不用 useCallback,假设这个回调函数也没有任何依赖状态,我直接把这个函数声明在组件外部不也可以吗?我直接使用 ref 不是更自由吗?
useMemo
本身名字就是和缓存有关联的,本质上就为了解决一个事情,在 render 里面不要直接创建对象或者方法什么的,因为组件每渲染一次,就会创建一次(比如 style 或者一些常量状态),造成不必要的资源浪费。理想情况应当是,如果存在依赖,只在依赖变化时重新创建,不存在依赖,那就只创建一次。表面上看,如果所有状态都用 useMemo,肯定没什么问题,但你还需从缓存的代价上来分析这个问题,如果使用 useMemo 缓存一个状态的代价大于它带来的优势,那是不是反而适得其反了?
大家对 useMemo
和 useCallback
有何看法,欢迎在下方评论或者加我讨论。
useImperativeHandle
定义
useImperativeHandle
可以让你在使用ref
时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用ref
这样的命令式代码。useImperativeHandle
应当与forwardRef
一起使用。
useImperativeHandle
作用 :子组件可以暴露给父组件 实例使用
格式: useImperativeHandle(ref,()=>{},[])
参数 1: 子组件向父组件暴露的实例
参数 2: 函数,传递的父组件可操作的实例和方法
参数 3: 监听状态,更新状态
useReducer
定义
它是
useState
的替代方案。它接收一个形如(state, action) => newState
的reducer
,并返回当前的state
以及与其配套的dispatch
方法。如果熟悉
Redux
使用的话,用useReducer
就是轻车熟路了,发车了。
使用Reducer
实现一个加减器
结语
❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创作
版权声明: 本文为 InfoQ 作者【HaiJun】的原创文章。
原文链接:【http://xie.infoq.cn/article/5f46374f07f8475413301e19d】。文章转载请联系作者。
评论