Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Router's useParams cause useEffect to rerun

I am using react-router 5.1 and react 16.10.

For a Master-Detail page, I am using useParams() to get the id from the url to open the page for the current group. Opening happens in a useEffect(). As a result, id has to be given as a dependency in that effect. However, when creating a new group, when there is enough data for a group to be valid, the API sends the id for that group and it sets the URL to /group/:id. As a result however, the effect runs again.

function Groups(props) {
  const { id } = useParams();
  const history = useHistory();

  const [group, setGroup] = useState(NEW_GROUP);

  const getData = useCallback(async () => {
    await Promise.resolve(Api.getGroups());
  }, []);

  const getGroup = useCallback(async group => {
    history.push(`/groups/${group.id}`);

    await Promise.resolve(Api.getGroup(group)).then(data => {
      setGroup(data.group);
    });
  }, [getData, history]);

  useEffect(() => {
    getData();

    if (id !== undefined) {
      getGroup({ id });
    }
  }, [props.actions, id, getData, getGroup]);

  // Saving data
  const saveGroup = useCallback(async () => {
    setSaved(SAVING);

    await Promise.resolve(Api.storeGroup(group)).then(data => {
        if (!group.hasOwnProperty('id')) {
            history.push(`/groups/${data.id}`);
            setGroup(prevGroup => ({ ...prevGroup, id: data.id }));
        }

        getData();
        setSaved(SAVED);
    }).catch(() => setSaved(FAILED));
  }, [getData, group, history]);
}

How do I prevent this from happening without breaking the "rules of hooks"?

like image 630
Yannick Avatar asked Oct 04 '19 11:10

Yannick


People also ask

What triggers useEffect?

By default useEffect will trigger anytime an update happens to the React component. This means if the component receives new props from its parent component or even when you change the state locally, the effect will run again.

Does useEffect run on every re render?

The useEffect Hook Usages. The callback function we pass to the useEffect hook runs the side effects. React runs it on every render of a component by default.

Is there any reason to return something from a useEffect hook?

Anatomy of the useEffect hookThe return function is the cleanup function, or when the user leaves the page and the component will unmount. The array is the last part, and it is where you put the states that will update throughout the component's lifecycle.

How do you trigger useEffect only once?

'); if(count < 1) { setTimeout(() => { setCount(count + 1); }, 1000); } return ( <div>Hello World</div> ); } export default App; In this code, the code inside useEffect will only get executed once even if we change the value of the variable count multiple times.


1 Answers

I had the same issue, and the way I solved is by passing the id from useParams to the function and set id only in useEffect.

function Groups(props) {
  const { id } = useParams();
  ...

  useEffect(() => {
    getData(id);

    if (id !== undefined) {
      getGroup({ id });
    }
  }, [id]);

 ...
}
like image 166
Kha Vu Avatar answered Oct 16 '22 20:10

Kha Vu