文章目录
什么是Hook
hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他 React 特性。
Hook 官方文档:Hooks
class组件的不足
- 组件之间难以复用状态逻辑
- 复杂组件难以理解
- 使用 class 导致学习成本变高
hook 使用注意事项
- Hook 不能再 class 组件中使用
- 只能在函数最外层调用 Hook ,不能在循环、条件判断或者子函数中调用
- 只能在 React 的函数组件中调用, 不能在其他 Javascript 函数中调用
内置Hooks
一、useState
如果检测到当前的state没有发生任何改变,那么页面是不会发生重新渲染的
使用方法
// 定义
const [count, setCount] = useState(0)
1、基本数据类型
# 更新
# 1、直接调用 setCount 传入更新的数据
setCount(count + 1)
# 2、对于复杂的更新逻辑使用函数式更新
setState(() => count + 1)
2、引用数据类型,使用函数式更新结合扩展运算符
const [state, setState] = useState({})
// 给 setState 传递一个函数,可以接收上一次state的结果(prevState)
setState((prevState) => {
return {
...prevState,
[key]: value
}
})
3、惰性初始state
initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略
4、复杂初始state定义
初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state
二、useContext
接收一个 context 对象并返回该 context 的当前值,使用 useContext 可以实现跨级组件之间的数据通信
三、useEffect
React 在完成对Dom的更新后会执行,默认情况下,React会在每次渲染后调用副作用函数,包括第一次渲染的时候。
useEffect 有两个参数,第一个参数是副作用的处理函数,第二个参数是与该副作用关联的状态或属性依赖数组
# 如果只想在初始化运行一次,后续不想再运行,那么可以给第二个参数传递一个空数组 [],达到componentDidMount一样的效果
# 如果需要清除监听逻辑,则可以返回一个函数,在函数中处理清除逻辑
# 初始化 useEffect 会被执行两次,这不是BUG 而是React18 的新特性,是为了模拟立即卸载组件和重新挂载组件。仅在'development' 环境下且使用了严格模式 ('Strict Mode') 下才会触发,生产环境 'production' 模式下和原来一样,仅执行一次。
useEffect(() => {
// 注册监听逻辑
console.log(state, 'useEffect')
// 清除监听逻辑
return () => {
// 清除监听逻辑
// 这里的逻辑在下一次执行useEffect的时候优先执行
}
}, [state])
四、useReducer
1、基础用法
# 接收三个参数,1、处理状态更新的reducer; 2、状态初始值; 3、状态初始化函数(可选),参数为第二个初始值,返回值为reducer的初始状态
const [state, dispatch] = useReducer(reducer, initialArg, init)
示例:
function reducer(state, action) {
switch(action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
case 'reset':
return { ...state, ...action.payload }
default:
throw new Error()
}
}
function init(initialCount) {
return { count: initialCount }
}
function Counter() {
const [state, dispatch] = useReducer(reducer, 1, init)
return (
<div>
<div>{ state.count }</div>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</div>
)
}
五、useCallback
在函数式组件中,定义在组件内的函数会随着状态值的更新而重新渲染,函数中定义的函数会被频繁定义,在父子组件的通信中这样是非常消耗性能的。
使用useCallback 结合 memo(React.memo) 可以有效的减少组件更新频率,提高效率
基本写法
# 第一个参数是处理函数,第二个参数是一个数组,用于指定被记忆函数更新所依赖的值,如果指定的值发生了变化,那么useCallback的处理函数就会被重新执行,否则useCallback始终返回上一次处理函数执行的结果(可以给useCallback第二个参数传递一个空数组,并将这个useCallback 当做props传递给其他组件,这样就不会导致子组件因为父组件的更新而被频繁更新)
const memoizedCallback = useCallback(
() => {
doSomething(a, b)
},
[a, b]
)
# React.memo用法, 只要传入的props 没有变动,那么组件就不会重新渲染
const Child = React.memo(function () {
return (
<div>child</div>
)
})
六、useMemo
1、把创建函数和依赖项数组作为参数传入 `useMemo`,它仅会在某个依赖项改变时才重新计算 memoized值。这种优化有助于避免在每次渲染时都进行高开销的计算。传入useMemo的函数会在渲染期间执行。
2、如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。
3、传入的函数内部必须要有返回值
# 实现类似 vue 的computed
const [a, setA] = useState(0)
const [b, setB] = useState(0)
const c = useMemo(() => {
return a + b
// 也可以返回一段 dom
// return <div>{a + b}</div>
}, [a, b])
持续更新中...