Open laclys opened 3 years ago
这样写法 也很丑。感觉hooks就是从一个坑跳入了一个更大的坑
note:
useDelayState
// useStateRef 消除依赖
function useStateRef<T>(val: T) {
const valRef = useRef(val);
useEffect(() => {
valRef.current = val;
}, [val]);
return valRef;
}
// useEndRef 检测销毁
function useEndRef() {
const endRef = useRef(false);
useEffect(() => {
return () => {
endRef.current = true;
};
}, []);
return endRef;
}
function useDelayState<T>(val: T, n = 100, ignore = false) {
const nRef = useStateRef(n);
const ignoreRef = useStateRef(ignore);
const endRef = useEndRef();
const [delayVal, setDelayVal] = useState<T | undefined>();
const handleTimeout = useCallback(() => {
if (endRef.current) return;
setDelayVal(val);
}, [val, endRef]);
useEffect(() => {
const timer = setTimeout(handleTimeout, nRef.current);
const ifIgnore = ignoreRef.current;
return () => {
if (ifIgnore) clearTimeout(timer);
};
}, [handleTimeout, nRef, ignoreRef]);
return delayVal;
}
所有函数式组件,服务中的视图元素,只要不是纯组件或者纯节点,原则上必须全部加 useMemo
Vue props 自带检查,v-memo 也是自动的。要用好React 心智负担确实比vue大很多
官方eslint
官方eslint配置之后,副作用函数有props或者state变量未存在于依赖数组中,会有
exhaustive-deps
规则的提醒。 然而一些场景下又与这些规则不符。 比如时间类函数类似componentDidMount
的功能一般会这么写:假设
var1
&var2
是我们通过 useState或者props传进来的变量。再或者,里面有函数执行,比如一些请求异步函数。然而这里我们没有在依赖数组中加入这些变量(deps)。就触发了exhaustive-deps
规则的提醒。黄色的小warning,大可不必理会。(自动lint --fix
一股脑把依赖添加到依赖数组里有时会出错)。强迫症出于对eslint的规则遵守。给出的解决方案就是 通过useRef来回避这个问题。对副作用函数中的每个变量都创建对应的useRef值。这样怎么说又麻烦有不合理。比如我们封装一个useMountwarning解除
再举个栗子
这样一个简单的例子。依旧触发了就触发了
exhaustive-deps
规则的提醒,有黄线。 但确确实实有这样的需求和问题。例子中Modal组件需要根据visible变量变化执行 ·”xxxxxx“一系列操作。操作中会引用其他变量比如这里的value
。但是我们确实不希望value
加在deps
中,因为我们并不关心它的变化。(需要引用到其它的 props 或 state 变量)如果把所有变量都加入deps
中带来的副作用可能会造成重复执行,这是非预期的也是没必要的事情(为了解决eslint小黄线而重复执行一次。这里 我们又迫于无奈需要一个辅助变量来记录 visible 变量的前一状态值,用来在副作用函数中判断是否因为 visible 变量变动触发的函数执行。我们又要用useRef
封装一个前值函数。希望 useEffect 的依赖数组中是与副作用函数更有效的变量,而不是副作用函数中全部引用的变量。
再说useCallback
在 类组件中,传递给子组件的
props
变量中函数大多数都是this.xxx
形式,即引用都是稳定的。useCallback 函数,只要依赖数组保持稳定,会返回一个引用稳定的函数。useCallback在项目中使用有时候会耗尽心思,一单一单 组件树上层一个不小心出了问题,有是前功尽弃 比如这么一个
App
组件包裹着Button
组件。我们希望disabled 和 onClick 变量的引用变动时才返回一个新的引用的函数。但是APP
组件这一层 没有用useCallback
包裹onBtnClick
保持函数稳定,每次传递给Button
的都是新函数(或者说全新的函数引用)子组件接收触发deps
,生成一个全新引用的handleBtnClick
函数。怎么办,这里我们再在子组件Button
中用useRef
解决问题我们用
useRef
-handleBtnClickRef
保存最新的函数。变量引用是固定的,所以 handleBtnClick 函数的引用也是固定的。触发 onClick 回调函数也能拿到最新的 disabled 和 onClick 值这里再举一个例子:需要得到一个不变的函数引用,但这个不变的函数执行的时候,执行的是传递的最新函数。这个实在
wukong
这各项目里用的。直接复制过来useRef
这里
useRef
成为了解决问题的关键。很像class里面的this.xxx
。mutable
的方式去解决问题。副作用、依赖数组真的增加了很多心智负担