I am using the following code to manage logged in user fetched from apollo
query in my React app.
import { useQuery } from '@apollo/client';
import { createContext, useEffect, useState } from 'react';
import { GET_USER } from './queries';
// Create a Context for logged in user (global state)
export const AuthContext = createContext();
function AuthProvider({ children }) {
const { loading, error, data } = useQuery(GET_USER);
const [user, setUser] = useState(null); // Global state
useEffect(() => {
if (!loading && !error && data.userInfo != null) {
setUser(data.userInfo);
}
}, [loading, error, data])
return (
<AuthContext.Provider value={{ user, setUser }}>
{children}
</AuthContext.Provider>
);
}
export default AuthProvider;
App.js
:
function App() {
return (
<div className="App">
<AuthProvider>
<NavigationBar />
<div className="main m-4">
<BrowserRouter>
...
</BrowserRouter>
</div>
<Footer />
</AuthProvider>
</div>
);
}
The problem is that the query is executed every time I re-render any component so it keeps "flashing". I would like the query to only happen once in the beginning. Any ideas how to do that?
Try moving the useQuery
call inside a child component that only mounts once, not directly in AuthProvider
.
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider value={{ user, setUser }}>
<UserFetcher />
{children}
</AuthContext.Provider>
);
}
function UserFetcher() {
const { loading, error, data } = useQuery(GET_USER);
const { setUser } = useContext(AuthContext);
useEffect(() => {
if (!loading && !error && data?.userInfo) {
setUser(data.userInfo);
}
}, [loading, error, data]);
return null;
}
This should ensure the query runs once on mount.