1

I have a router state "refetch" that triggers the component to refetch its data (instead of using the cached one), but when it's done, I'd like to toggle that state back to avoid an infinite loop. What is the best way to change state parameters? Or this approach is wrong?

const { state } = useLocation<{ refetch: boolean }>()
  
const query = useQuery<....>()
    
useEffect(() => {
  if (state.refetch) {
    query.refetch()
    state.refetch = false // feels wrong to me
  }
}, [query, state])
ash
  • 1,065
  • 1
  • 5
  • 20
Endre Szabó
  • 554
  • 3
  • 9
  • When and how often do you want this effect to run? This approach does seem incorrect, it's mutating the `state` object. Can you clarify your use case? – Drew Reese Apr 19 '22 at 15:52
  • Ye exactly, feels wrong. But how do I toggle the refetch state then? I want this to run whenever the state changes to refetch = true – Endre Szabó Apr 19 '22 at 20:46
  • Can you share how this "flow" is initiated? In other words, what is setting the route state? Can we see a more complete code example? – Drew Reese Apr 19 '22 at 20:54
  • Can't really :( This is it. From another page (component) I navigate to this page this way: history.push(pathToPage, { refetch: true }) I use it as a replacemenet for query params – Endre Szabó Apr 20 '22 at 06:29
  • That's enough, I think. – Drew Reese Apr 20 '22 at 06:30

2 Answers2

1

I think instead of mutating the route state object you could issue a redirect with the refetch state set false.

Example:

const history = useHistory();
const { pathname, state } = useLocation();
  
const query = useQuery<....>();
    
useEffect(() => {
  if (state.refetch) {
    query.refetch();
    history.replace(pathname, { refetch: false });
  }
}, [query, state]);
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 1
    Ye I was wondering this approach would be nicer. If there is not any other superfancy way, gonna stick with this one, ty :) – Endre Szabó Apr 20 '22 at 06:47
  • But history.replace does redirects right? Not the best ux – Endre Szabó Apr 21 '22 at 10:51
  • @EndreSzabó That's subjective I suppose, but I would think allowing back navigation to the "intermediate" page with the `refetch` state true would be undesired. You are handling the refetch and then "fixing" the history stack so if the user navigates back they go back to the page they were on ***prior*** to landing on this page with the fetching logic. Does this make sense? – Drew Reese Apr 21 '22 at 16:43
1

If you're using React Query, you don't need to add an useEffect for that, you can add dependencies to a query, passing an array as the query key, eg:

useQuery(['key', ...dependencies], queryFn);

Every time the dependencies change it will refetch the query.

In your case you could try useQuery(['key', state], queryFn);

If you need to stick to the refetch of the history, you could add the toggle to the queryFn

Query Keys - React Query

If your function depends on a variable include it in your query key - Stack Overflow

PD: You shouldn't use an object or array as a dependency for useEffect or useMemo, etc. That will always cause an infinite loop. You could stringify them first using JSON.stringify(foo), use a property of the object, maybe the length of the array. Personally, I stringify them, that way the comparison is more accurate.

Raul Luis
  • 36
  • 3