停止 useEffect 在挂载上运行

IT技术 reactjs react-redux react-hooks use-effect
2021-03-29 07:01:48

我只希望 useEffect 在我的依赖项列表更改时运行,它也在每次挂载组件时运行,有什么方法可以不在挂载时触发?

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

我最初认为这意味着它不应该在后续的装载上重新渲染,但这个问题澄清了这一点。

我在主“页面”(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]);
2个回答

你不能开箱即用地配置它。

但是,一个常见的模式是使用一些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]);
};
我相信第二个示例存在一个错误,即“是第一个渲染”。而不是isFirstRender = false应该isFirstRender.current = false
2021-06-11 07:01:48
@GregL 谢谢你是对的
2021-06-18 07:01:48

如果您一开始有几个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。