推荐阅读
在实践中, 我们(我)经常会遇到, 当某变量变化的时候, 执行其他方法(副作用), 通常我们使用 useEffect
:
function useHook() {
const [varA] = useState();
useEffect(() => {
// do something
}, [varA]);
}
但是如果执行的方法中包含其他响应式变量 varB
, 我们需要 varB
的最新值, 但却不希望 varB
变化时触发 useEffect
重新执行, 那我们可能需要 hack:
function useHook() {
const [varA] = useState();
const [varB] = useState();
// mui 的 useEventCallback
const effect = useEventCallback(() => {
doSomething(varB);
});
useEffect(() => {
effect();
}, [varA, effect]);
}
因此我们可以写一个小小的语法糖来简化这一目的:
export function useListen<T>(
value: T,
// prev 需要可能为 undefined, 因为初次渲染时, prev 就是 undefined
callback: (next: T, prev: T | undefined) => void
) {
const prevRef = useRef(value);
const callbackRef = useRef(callback);
callbackRef.current = callback;
useEffect(() => {
/**
* useEffect 在 dev 环境会执行 2 遍, 此处避免该行为造成的影响;
* 因为我们该方法的目的与 useEffect 单纯的 "执行幂等的副作用" 不同,
* 该方法的目的就是变量改变的时候执行 callback, 并不要求 callback 幂等,
* 所以不应该执行 2 遍;
*/
if (value === prevRef.current) {
return;
}
callbackRef.current(value, prevRef.current);
prevRef.current = value;
}, [value]);
}
function Test() {
const [varA, setVarA] = useState()
useListen(varA, (next, prev) => {
console.log({ next, prev })
})
// ...
}
语义明晰
免除各种冗余的格式代码
useListen(varA, () => {
// 错误用法, 因为没有消除副作用 (removeEventListener)
window.addEventListener('event-name', callback)
})
版权声明: 自由转载-非商用-非衍生-保持署名 (创意共享 3.0 许可证)