停止在挂载上运行 useEffect

Posted

技术标签:

【中文标题】停止在挂载上运行 useEffect【英文标题】:Stop useEffect from running on mount 【发布时间】:2020-04-16 22:40:00 【问题描述】:

我只希望useEffect在我的依赖列表发生变化时运行,每次挂载组件时它也运行,有什么办法在挂载时不触发?

如果某些值,你可以告诉 React 跳过应用效果 重新渲染之间没有变化。

我最初认为这意味着它不应该在后续安装时重新渲染,而是 this question cleared that up.

我在主“页面”(react-router)中显示记录列表,用户可以选择单个记录并转到详细信息页面,然后返回主页面 - 所以主列表组件是在那种情况下完全卸载/安装。每次我加载“母版页”时,我都会看到正在获取的数据,我只希望在其中一个依赖项发生变化时发生这种情况;这些依赖项和数据本身都存储在 Redux 中,因此它们是全局的。

是否可以使 useEffect 或其他挂钩仅在依赖项更改时触发?

const page, pageSize, search, sorts = useSelector(getFilters);
const data = useSelector(getData);

useEffect(() => 

  console.log("fetching");
  dispatch(fetchData(page, pageSize, search, sorts));

, [page, pageSize, search, sorts]);

【问题讨论】:

【参考方案1】:

您不能开箱即用地对其进行配置。

但是,一个常见的模式是像这样使用一些isMounted 标志:

// Is Mounted
const useFetchNotOnMount = () => 
  ...
  const isMounted = useRef(false);

  useEffect(() => 
    if (isMounted.current) 
      console.log('fetching');
      dispatch(fetchData(filters));
     else 
      isMounted.current = true;
    
  , [dispatch, filters]);
;

// Same (Is First Render)
const useFetchNotOnMount = () => 
  ...
  const isFirstRender = useRef(true);

  useEffect(() => 
    if (isFirstRender.current) 
      isFirstRender.current = false;
     else 
      console.log("fetching");
      dispatch(fetchData(filters));
    
  , [dispatch, filters]);
;
深入了解uses of useEffect

【讨论】:

我相信第二个示例存在错误,即“第一次渲染”示例。而不是isFirstRender = false,它应该是isFirstRender.current = false @GregL 谢谢你是对的【参考方案2】:

如果您有多个useEffect 最初需要阻止运行,您可以执行以下操作:


export default function App() 
  const mountedRef = useMountedRef();
  const [isLoggedIn, setLoggedIn] = React.useState(false);
  const [anotherOne, setAnotherOne] = React.useState(false);

  React.useEffect(() => 
    if (mountedRef.current) 
      console.log("triggered", isLoggedIn);
    
  , [isLoggedIn]);

  React.useEffect(() => 
    if (mountedRef.current) 
      console.log("triggered", anotherOne);
    
  , [anotherOne]);

  React.useEffect(() => 
    if (mountedRef.current) 
      console.log("triggered", isLoggedIn, anotherOne);
    
  , [anotherOne, isLoggedIn]);

  return (
    <div>
      <button onClick=() => setLoggedIn(true)>Login</button>
    </div>
  );


const useMountedRef = () => 
  const mountedRef = React.useRef(false);

  React.useEffect(() => 
    setTimeout(() => 
      mountedRef.current = true;
    );
  , []);

  return mountedRef;
;

演示:https://stackblitz.com/edit/react-eelqp2

有一点很重要,您必须使用setTimeout 进行合理的延迟,以确保在所有初始 useEffects 之后将 ref 值设置为 true。

【讨论】:

以上是关于停止在挂载上运行 useEffect的主要内容,如果未能解决你的问题,请参考以下文章

docker-修改容器挂载目录的3种方法小结

在 Java 中运用动态挂载实现 Bug 的热修复

linux 的jobs命令

React 功能组件在重新挂载后停止渲染状态更改

磁盘数据迁移记录

磁盘数据迁移记录