Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop useEffect from running on mount

I only want useEffect to run when my dependency list changes, it is also running every time the component is mounted, is there any way to not fire on mount?

You can tell React to skip applying an effect if certain values haven’t changed between re-renders.

I initially thought that meant it shouldn't re-render on subsequent mounts but this question cleared that up.

I am displaying a list of records in a master "page" (react-router), the user can choose a single record and go to the detail page, and then return to the master page - so the master list component is completely unmounted/mounted in that scenario. And every time I load the "master page", I see the data being fetched, I only want this to happen when one of the dependencies changes; these dependencies and the data itself are stored in Redux so they're global.

Can useEffect or another hook be made to only fire when the dependencies change?

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]);
like image 365
user210757 Avatar asked Dec 26 '19 19:12

user210757


People also ask

Does useEffect fire on Mount?

Important: the useEffect hook will always run on mount regardless of if there is anything in its dependency array. We probably don't want to actually run this effect on our data when it's undefined (as it will be on initial render) but rather we want to wait until it is populated from the API call.

How do I stop useEffect from running on first render?

We can make the React useEffect callback not run on the first render by creating a ref that keeps track of whether the first render is done. Then we can check the ref's value to see when the first render is done and run the function we want when the first render is done.


Video Answer


2 Answers

You can't configure it out of the box.

But, a common pattern is to use some isMounted flag like so:

// 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]);
};
  • Read more in depth uses of useEffect
like image 189
Dennis Vash Avatar answered Oct 16 '22 13:10

Dennis Vash


If you have several useEffect to prevent from running at initially, you can do the following:


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;
};

Demo: https://stackblitz.com/edit/react-eelqp2

One thing important is that you have to use setTimeout to make a reasonable delay to make sure that the ref value is set to true after all initial useEffects.

like image 31
Ever Avatar answered Oct 16 '22 12:10

Ever