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缓存函数
useReducerredux 相似
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】。文章转载请联系作者。











评论