Ade*_*mes 5 javascript reactjs react-hooks use-effect
这是一个 React 风格的问题。
TL;DR从setReact 的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
如果这改变了每个渲染,我们如何使用它运行一次效果呢?
如果您确实希望效果仅在组件安装时运行一次,那么使用空依赖项数组是正确的。您可以禁用该行的 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
}, []);
注意:如果您稍后更新效果并且它需要在其他依赖项之后运行,那么此禁用的注释可能会掩盖未来的错误,因此我建议留下一个相当公开的注释,以说明覆盖已建立的 linting 规则的原因。
或者,您可以使用反应引用来表示初始渲染。这比使用某种状态来保存值更好,因为更新它会触发不必要的渲染。
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>
  );
}
是的,如果您发现这种“单次运行逻辑”在代码库中反复使用,那么您绝对可以将其纳入自定义挂钩中。
| 归档时间: | 
 | 
| 查看次数: | 1502 次 | 
| 最近记录: |