For a React project, I'm using multiple context providers running GraphQL queries, providing all, or some components with my needed data. For this example, I have a BookProvider that queries all the books for a specific user.
export const BookProvider = ({ children }) => {
// GraphQL query for retrieving the user-belonged books
const { loading, data } = useQuery(gql`{
books {
id,
name,
description
}
}
`, {
pollInterval: 500
})
if(!data?.books) return null
return (
<BookContext.Provider value={data?.books}>
{!loading && children}
</BookContext.Provider>
)
}
I made sure the query wasn't loading and is available in the data
object. For retreiving my data, I have a dashboard component wrapped in this provider. In here, there are other components loading the corresponding data.
const Dashboard = () => {
return (
<BookProvider>
// More components for loading data
</BookProvider>
)
}
The data is loaded like this:
const { id, name } = useContext(BookContext)
In the same way, I have a AuthenticationProvider
, wrapping the whole application.
export const MeQuery = gql`{ me { id, email } }`
export const AuthenticationProvider = (props) => {
const { loading, data } = useQuery(MeQuery)
if(loading) return null
const value = {
user: (data && data.me) || null
}
return <AuthenticationContext.Provider value={value} {...props} />
}
For my application routes, checking if the user is authenticated, I use a PrivateRoute
component. The Dashboard
component is loaded by this PrivateRoute
.
const PrivateRoute = ({ component: Component, ...rest }) => {
const { user } = useAuthentication()
return user ? <Route {...rest} render={props => <Component {...props} />} /> : <Redirect to={{ pathname: '/login' }} />
}
When logging in, and setting the user object, there is no problem, however, when logging out, which is a component on the Dashboard
, it re-directs me to the login page, but I receive the following error:
index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
at BookProvider (http://localhost:3000/static/js/main.chunk.js:2869:3)
at Dashboard
at Route (http://localhost:3000/static/js/vendors~main.chunk.js:85417:29)
at PrivateRoute (http://localhost:3000/static/js/main.chunk.js:4180:14)
at Switch (http://localhost:3000/static/js/vendors~main.chunk.js:85619:29)
at Router (http://localhost:3000/static/js/vendors~main.chunk.js:85052:30)
at BrowserRouter (http://localhost:3000/static/js/vendors~main.chunk.js:84672:35)
at Router
For logging out, I'm using the following code:
export function useLogout() {
const client = useApolloClient()
const logout = useMutation(gql`mutation Logout { logout }`, { update: async cache => {
cache.writeQuery({ query: MeQuery, data: { me: null }})
await client.resetStore()
}})
return logout
}
export default useLogout
This gets called like const [logout] = useLogout()
Questions
I'll give it another try ;-)
You would use useLazyQuery
instead, that seem to allow avoiding the bug that plagues useQuery
:
const [ executeQuery, { data, loading } ] = useLazyQuery(gql`${QUERY}`);
And then manage the polling manually:
useEffect(function managePolling() {
const timeout = null
const schedulePolling = () => {
timeout = setTimeout(() => {
executeQuery()
schedulePolling()
}, 500)
}
executeQuery()
schedulePolling()
return () => clearTimeout(timeout)
}, [executeQuery])
(untested code, but you get the idea)
This was suggested on the same thread (https://github.com/apollographql/apollo-client/issues/6209#issuecomment-676373050) so maybe you already tried it...