T
TanStack3y ago
rare-sapphire

Best way to have an inactivity timer in react-query?

Essentially, if a user is inactive for 30 minutes we want to prompt them to remain active or automatically log them out. My question is what's the best approach to restart a countdown timer when query/mutations happen? - My own QueryCache/MutationCache with onSuccess calling to a provider/store? - Subscribe within my component using mutationCache/queryCache.subscribe? - Something else? I was using this article as my reference, which is what I used for our ErrorModal popup: https://tkdodo.eu/blog/react-query-error-handling#the-global-callbacks
React Query Error Handling
After covering the sunshine cases of data fetching, it's time to look at situations where things don't go as planned and "Something went wrong..."
6 Replies
optimistic-gold
optimistic-gold3y ago
I would probably do this at a lower level, when actually sending the requests, inside the query function. You could wrap fetch (or whatever you use to send a request) into a function that would also reset the timer.
rare-sapphire
rare-sapphireOP3y ago
We use ky for our requests and I thought of doing afterResponse but then that creates the difficulty of being outside of a React component, which I don't know how to best solve In my React DOM I basically have {isExpiring && <MyModal />} where isExpiring is set to true once our timeout is hit via useTimeout from usehooks-ts. If I'm doing something in ky's afterResponse I couldn't find a good way to do React things from outside a component. It seems pretty frowned upon (which I why I tried moving the logic into react-query)?
optimistic-gold
optimistic-gold3y ago
I would probably use the window for this. Here is a working example: https://codesandbox.io/s/gallant-sun-vsrvf4?file=/src/index.js A callback to refresh the timer is placed on the window and the custom fetch function can trigger it every time it runs. Since that callback is created inside of react, we are still able to set the isExpired state inside it thanks to closure. And the isExpired state value is propagated through context. I suspect something can be done using useSyncExternalStore() too
CodeSandbox
gallant-sun-vsrvf4 - CodeSandbox
gallant-sun-vsrvf4 using axios, react, react-dom, react-query, react-scripts, stop-runaway-react-effects, styled-components, usehooks-ts
rare-sapphire
rare-sapphireOP3y ago
The problem is our sessions are stored server side so I need to actually touch the server to truly remain active. This effort is rewritting a very old AngularJS project in React so I could give some details on how the old system works if that'd help.
optimistic-gold
optimistic-gold3y ago
Does this change the timer logic?
rare-sapphire
rare-sapphireOP3y ago
It does a little but I looked at your example closer and I think it gives me an idea Okay so I've moved my logic into ky like I originally wanted and since we're using zustand I'll have something like useAuthStore.getState().restartTimer()

Did you find this page helpful?