Appearance
上一篇在写 useRequest 的时候,其中有些可以复用的 hooks
,我们这一篇把相关的 hooks
拿出来,简洁描述下,具体 hooks
的名字不用太关注,我们主要关注其使用的场景。
该hook
主要是用来记忆上一次的值的,一般使用场景为需要有对比当前值以及上一次的值的时候。具体实现比较容易理解,代码如下:
import { useEffect, useRef } from 'react'
// 版本1
export default function usePrevious(state) {
const previousRef = useRef()
const currentRef = useRef()
useEffect(() => {
previousRef.current = currentRef.current
currentRef.current = state
}, [state])
return previousRef.current
}
// 版本2
export function usePrevious2(state) {
const previousRef = useRef()
const currentRef = useRef()
previousRef.current = currentRef.current
currentRef.current = state
return previousRef.current
}
// 版本3
export function usePrevious3(state) {
const previousRef = useRef()
const currentRef = useRef()
if (!Object.is(currentRef.current, state)) {
previousRef.current = currentRef.current
currentRef.current = state
}
return previousRef.current
}
使用 2 个 Ref
记录当前 state
和上一个 state 值
,如果当前 state
监听到有改动,则进行重新赋值,最终返回的是上一个 state
值。其中赋值这里逻辑为:先把 当前 state
赋值给 上一个 state
. 再把最新 state
赋值给 当前 state
该 hook
主要是二次封装 useEffect
对其 deps 进行值的比较,如果值不同才会执行对应回调函数。使用场景可以对比 useEffect
, 例如:
const [params, setParams] = useState({ search: '' })
useCompareEffect(() => {
fetch('xx')
}, [params])
以上例子,当 params.search
值改变,才会进行请求。功能分析的话,该 hook
需要实现如下功能
state
state
的值是否相等第一点使用上面的 usePrevious
便可, 第二点也有很多实现方式,我们先假设已有此功能函数。 先关注核心 useCompareEffect
的实现逻辑。
import { isEqual } from '@slsanyi/utils'
// 方式一
export function useCompareEffect1(fn, deps) {
const preValue = usePrevious(deps)
useEffect(() => {
if (isEqual(preValue, deps)) return
return fn()
}, deps)
}
// 方式二
export function useCompareEffect2(fn, deps) {
const preValue = usePrevious(deps)
const signalRef = useRef(0)
if (!isEqual(preValue, deps)) {
signalRef.current += 1
}
useEffect(fn, [signalRef.current])
}
其中以上代码中,方式一 会在React.StrictMode
模式下,出现异常,原因在于严格模式下,App
组件执行了 2 次,其中 useRequest
也运行 2 次,useCompareEffect
也运行 2 次,usePrevious
也运行 2 次。
// usePrevious
// 1 => pre = 0,cur = 1.
// 1 => pre = 1, cur = 1
假设 usePrevious(1)
执行 2 次, 第一次 最终值为 cur = 1, pre = 0
, 第二次再执行就变成了 cur = 1, pre = 1
. 最终造成了异步执行的回掉函数函数 useEffect
第一个参数在判断是否 相等的时候,因为 上一次和当前的 state
相同,所以没有执行到最终的函数.
方式二通过判断不同的情形,再执行 useEffect
,从而保证只有不等的时候执行一次副作用回掉函数函数。