更新时间:2022-06-12 22:19:58
我个人总是禁用 eslint 规则.由于 eslint 无法理解你的逻辑内涵,它只能彻底检查闭包中捕获的所有变量,并警告你从 dep-list 中丢失的变量.但是很多时候它是矫枉过正的,就像在您的用例中一样.这就是我选择的理由.
I personally always disable that eslint rule. Due to that eslint has no way to understand your logical intension, it can only exhaustively check all variables captured in the closure and warn you about missing ones from dep-list. But a lot of time it's overkilling, just like in your use case. That's the reasoning behind my choice.
如果您清楚地了解 useEffect
的工作原理,禁用此规则不会造成太大的痛苦.我个人不记得经历过.
If you have a clear understanding of how useEffect
works, disabling this rule wouldn't cause much pain. I personally don't remember experiencing it.
第二种解决方案是保留规则,但要解决它.我为你准备了一个,useFn
自定义钩子:
A second solution is to leave the rule on, but work around it. I got one for you, the useFn
custom hook:
function useFn(fn) {
const ref = useRef(fn);
ref.current = fn;
function wrapper() {
return ref.current.apply(this, arguments)
}
return useRef(wrapper).current
}
这个钩子返回一个wrapper
函数的稳定引用,它只是一个调用实际fn
的代理,但在重新渲染时不会改变.>
This hook returns a stable reference of wrapper
function, which is just a proxy that call the actual fn
, but doesn't change across re-rendering.
const SimpleComponent = (props: Props) => {
const {id, callback: _callback} = props;
const callback = useFn(_callback)
useEffect(() => {
callback(id)
}, [id, callback]);
return <div/>
};
现在你满足了 eslint 规则,同时你不会触发不需要的 useEffect
重新运行.
Now you satisfy that eslint rule meanwhile you don't trigger unwanted useEffect
re-run.
作为题外话.我还使用 useFn
钩子来包装传递给子组件的 props 的函数.
As an off-topic side note. I also use useFn
hook to wrap functions that got passed to child components' props.
传递箭头函数是 React 中大量使用的模式.有时你有一个重新渲染的组件很昂贵,你 React.memo(Component)
包装它,然后你传递一个
内联函数,有效地使 memoize 效果失效.useFn
来拯救:
Passing arrow function around is heavily used pattern in React. Sometimes you have a component that's expensive to re-render, you React.memo(Component)
wrap it, yet then you pass a <Component onClick={e => { ... }} />
inline function, which effectively invalidate the memoize effect. useFn
comes to rescue:
<Component onClick={useFn(e => { ... })} />