这是一个 React 风格的问题。
TL;DR 采取set
来自 React 的 useState
的函数.如果该函数在每次渲染时都“改变”了,那么在 useEffect
中使用它的最佳方式是什么? ,效果只运行一次?
解释我们有一个 useEffect 需要运行一次(它获取 Firebase 数据),然后将该数据设置为应用程序状态。
这是一个简化的例子。我们正在使用 little-state-machine , 和 updateProfileData
是更新 JSON 状态的“配置文件”部分的操作。
const MyComponent = () => {
const { actions, state } = useStateMachine({updateProfileData, updateLoginData});
useEffect(() => {
const get_data_async = () => {
const response = await get_firebase_data();
actions.updateProfileData( {user: response.user} );
};
get_data_async();
}, []);
return (
<p>Hello, world!</p>
);
}
然而,ESLint 不喜欢这样:React Hook useEffect has a missing dependency: 'actions'. Either include it or remove the dependency array
这是有道理的。问题是这样的:actions
每次渲染都会改变——更新状态会导致重新渲染。一个无限循环。取消引用
updateProfileData
也不起作用。使用这样的东西是一种好习惯吗:单次运行
useEffect
?可能/可能不起作用的概念代码:
const useSingleEffect = (fxn, dependencies) => {
const [ hasRun, setHasRun ] = useState(false);
useEffect(() => {
if(!hasRun) {
fxn();
setHasRun(true);
}
}, [...dependencies, hasRun]);
};
// then, in a component:
const MyComponent = () => {
const { actions, state } = useStateMachine({updateProfileData, updateLoginData});
useSingleEffect(async () => {
const response = await get_firebase_data();
actions.updateProfileData( {user: response.user} );
}, [actions]);
return (
<p>Hello, world!</p>
);
}
但是到那时,为什么还要关心依赖数组呢?显示的初始代码有效且有意义(闭包保证正确的变量/函数),ESLint 只是建议不要这样做。这就像如果 React 的第二个返回值
useState
更改了每个渲染:const [ foo, setFoo ] = useState(null);
// ^ this one
如果这改变了每次渲染,我们如何用它运行一次效果?
最佳答案
忽略 line 的 eslint 规则
如果您真的希望效果在组件安装时只运行一次,那么使用空依赖数组是正确的。您可以禁用该行的 eslint 规则以忽略它。
useEffect(() => {
const get_data_async = () => {
const response = await get_firebase_data();
actions.updateProfileData( {user: response.user} );
};
get_data_async();
// NOTE: Run effect once on component mount, please
// recheck dependencies if effect is updated.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
注:如果您稍后更新效果并且它需要在其他依赖项之后运行,那么这个禁用的注释可能会掩盖 future 的错误,所以我建议留下一个相当 公开评论覆盖已建立的 linting 规则的原因。自定义钩子(Hook)逻辑
或者,您可以使用 react ref 来表示初始渲染。这比使用某些状态来保存值更可取,因为更新它会触发不必要的渲染。
const MyComponent = () => {
const { actions, state } = useStateMachine({updateProfileData, updateLoginData});
const initialRenderRef = useRef(true);
useEffect(() => {
const get_data_async = () => {
const response = await get_firebase_data();
actions.updateProfileData( {user: response.user} );
};
if (initialRenderRef.current) {
initialRenderRef.current = false;
get_data_async();
}
}, [actions]); // <-- and any other dependencies the linter complains about
return (
<p>Hello, world!</p>
);
}
是的,如果它是您发现在代码库中反复使用的模式,您绝对可以将这种“单次运行逻辑”纳入自定义 Hook 。
关于javascript - 使用快乐的 ESLint 运行一次 useEffect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65693657/