Reputation: 12054
I'm using React and Graphql and Apollo.
My index.js is as follows:
const client = new ApolloClient({
uri: GRAPHQL_URL,
fetchOptions: {
credentials: 'include'
},
request: (operation) => {
const token = localStorage.getItem(AUTH_TOKEN_KEY) || "";
operation.setContext({
headers: {
Authorization: `JWT ${token}`
}
})
},
clientState: {
defaults: {
isLoggedIn: !!localStorage.getItem(AUTH_TOKEN_KEY)
}
}
});
const IS_LOGGED_IN_QUERY = gql`
query {
isLoggedIn @client
}
`;
ReactDOM.render(
<ApolloProvider client={client}>
<Query query={IS_LOGGED_IN_QUERY}>
{({data}) => {
return data.isLoggedIn ? <App/> : <Login/>
}}
</Query>
</ApolloProvider>,
document.getElementById('root')
);
Thus if user is logged in I save token to localStorage
and the <App />
is shown instead of <Login />
The <Login />
is as follows:
const Login = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [logIn, { loading: mutationLoading, error: mutationError }] = useMutation(LOG_IN_MUTATION);
const client = useApolloClient();
const handleSubmit = async (e) => {
e.preventDefault();
const res = await logIn({variables: {username, password}});
client.writeData({ data: { isLoggedIn: true } })
localStorage.setItem(AUTH_TOKEN_KEY, res.data.tokenAuth.token);
};
return ( ... )
In de <App />
I do a Graphql query to the backend to get de data of currently logged in user. That stuck code in the backend works as expected.
The <App />
is as follows:
function App() {
const {loading, error, data} = useQuery(GET_ME);
if (loading) return <div><LoadingIndicator1/></div>
if (!loading && error) return <div ><ErrorIndicator/></div>
return (
...
);
}
export default App;
And the GET_ME
query is as follows:
export const GET_ME = gql`
{
me{
id
username
firstName
lastName
email
}
}
`;
The function for logging out is as follows:
const client = useApolloClient();
const signOut = (client) => {
localStorage.removeItem(AUTH_TOKEN_KEY);
client.writeData({
data: {
isLoggedIn: false
}
})
};
But the problem is when I log in with one user and the logout, then login with the other user, i still see the old one. If I then refresh I see the new user.
Any idea what I do wrong?
UPDATE
The <App />
component is as follows:
function App() {
const {loading, error, data} = useQuery(GET_ME);
if (loading) return <div><LoadingIndicator1/></div>
if (!loading && error) return <div ><ErrorIndicator/></div>
return (
<Router>
<UserContext.Provider value={data.me}>
<ToastProvider>
<Header/>
<Switch>
<Route path="/report/:id">
<NewReport/>
</Route>
<Route exact path="/report/">
<NewReport/>
</Route>
<Route path="/reports/">
<Reports/>
</Route>
<Route exact path="/">
<Home/>
</Route>
</Switch>
</ToastProvider>
</UserContext.Provider>
</Router>
);
}
And component where I use the user details is as follows:
render (
<div>
{localStorage.getItem(AUTH_TOKEN_KEY) !== null && <div>
<div className=''>
<span>{currentUser.username}</span>
<i className="fad fa-angle-down" />
</div>
</div>}
</div>
)
Upvotes: 0
Views: 1628
Reputation: 8418
I do it in main component () and then pass it via React Context to all child components.
I want to do it on one place and pass it down as props.
Using context duplicates already existing apollo client context. You can simply useQuery
to get the same (cache-only
if you want).
Other hints:
<Query query={IS_LOGGED_IN_QUERY}>
) should be a FC (with useQuery
hook) and combined into <App/>
component;me
is defined then user is logged in (unnecessary state duplication) - you can combine them in one query;... probably caused by cached results of GET_ME
query. It's not network-only
neither parametrized by some user id variable.
From Apollo docs (auth):
The easiest way to ensure that the UI and store state reflects the current user's permissions is to call
client.resetStore()
after your login or logout process has completed.
Upvotes: 2