react Hooks浅谈
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性
useState
import React,{useState} from 'react'
function HelloWorld(){
const [count, setCount]=useState(0);
return (
<div>
<p>{count}次</p>
<button onClick={()=>setCount(count+1)}>点击</button>
</div>
)
}
useState 它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并;useState中0属于初始值,初始 state 参数只有在第一次渲染时会被用到;
useEffect
import React,{useState,useEffect} from 'react'
function HelloWorld(){
const [count, setCount]=useState(0);
// 相当于componentDidMount 和 componentDidUpdate
useEffect(()=>{
// 使用浏览器的Api更新页面标题
document.title=`${count}次`
})
return (
<div>
<p>{count}次</p>
<button onClick={()=>setCount(count+1)}>点击</button>
</div>
)
}
useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API
Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:
1、只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
2、只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。
并非所有 effect 都可以被延迟执行。例如,一个对用户可见的 DOM 变更就必须在浏览器执行下一次绘制前被同步执行,这样用户才不会感觉到视觉上的不一致。(概念上类似于被动监听事件和主动监听事件的区别。)React 为此提供了一个额外的 useLayoutEffect Hook 来处理这类 effect。它和 useEffect 的结构相同,区别只是调用时机不同。
useContext
const value = useContext(MyContext);
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。
当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用 React.memo 或 shouldComponentUpdate,也会在组件本身使用 useContext 时重新渲染。
useReducer
import { useReducer } from 'react'
const updateReducer = (num: number) => (num + 1) % 1_000_000
/**
* 让组件触发一次刷新操作
*/
const useUpdate = () => {
const [, update] = useReducer(updateReducer, 0)
return update
}
export default useUpdate
两种方式
1, 将初始 state 作为第二个参数传入 useReducer 是最简单的方法
2, 惰性地创建初始 state。为此,需要将 init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被设置为 init(initialArg)。
useCallback
useMemo
import React,{useMemo,useState,useEffect} from 'react'
useMemo(
() =>
schema.enum?.map((item: any) => ({
name: item.value,
})),
[schema]
)
注:传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。
如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值
useRef
import React,{useRef} from 'react'
function HelloWorld(props){
const valueRef = useRef({})
const value = { ...valueRef.current }
}
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变
useImperativeHandle
useLayoutEffect
import {useLayoutEffect} from 'react'
useLayoutEffect(() => {
cropperRef.current = new Cropper(imgRef.current, {
...cropperProps
})
return () => {
cropperRef.current?.destroy()
}
}, [cropperProps])
其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
尽可能使用标准的 useEffect 以避免阻塞视觉更新。

浙公网安备 33010602011771号