Home > Back-end >  React router redirection causes useEffect to trigger twice
React router redirection causes useEffect to trigger twice

Time:06-01

I have a route defined as following:

<Route path={`list`} element={<ListPage />}>
  <Route path={`sidePanel1`} element={<SidePanel1 />} />
  <Route path={`sidePanel2`} element={<SidePanel2 />} />
  <Route index element={<Navigate to={`sidePanel1`} replace />}/>
</Route>

So, when /list is typed it will be redirected to /list/sidePanel1.

in the ListPage component I have this:

const ListPage = (): JSX.Element => {
  const [data, setData] = useState<ListDto[]>([]);

  const location = useLocation();

  useEffect(() => {

    getList()
      .then(response => {
        setData(response.data);
      })
      .catch(() => {
        setIsLoading(false);
      });
  }, [location]);
  return (
    <ListTable data={data}/>
    <SidePanelStyles>
       <Outlet />
    </SidePanelStyles>
  );
};

So, my problem is that whenever I type /list/ the useEffect will trigger since the location has changed, and then it will trigger for the second time when redirected to /list/sidePanel1.

I want it to only be triggered after I get redirected.

How can I solve this ?

CodePudding user response:

Instead of redirecting and rendering twice, just render SidePanel1 component on the index route as well.

Example:

<Route path="list" element={<ListPage />}>
  <Route index element={<SidePanel1 />} />
  <Route path="sidePanel1" element={<SidePanel1 />} />
  <Route path="sidePanel2" element={<SidePanel2 />} />
</Route>

CodePudding user response:

One general-purpose solution to only react to the last change in a quick sequence of changes is to use a "debounce".

I.e. a delay between when the effect is triggered and when getList is called, so that if the effect is triggered again before the delay is finished, the pending call will be canceled.

function useDebouncedEffect(delay, effect, triggerParams) {
  useEffect(() => {
    const timeout = setTimeout(f, delay)
    return () => clearTimeout(timeout)
  }, triggerParams)
}

useDebouncedEffect(300, () => {
  getList()
    .then(response => {
      setData(response.data);
    })
    .catch(() => {
      setIsLoading(false);
    });
  }, [location]);
  • Related