We need to refresh the page after logging in new user for the detail of new user in graphql otherwise it show the previous loggedin user's detail

Viewed 59

I am creating quote app using react,graphql,apollo-client,mongodb atlas. I am storing authentication token in the localStorage when user login and remove it when user logout.I have a profile page in which it shows the detail of loggedin user.

The issue is that when i logout and then login another user,it shows the detail of previous user and when i refresh the page then it shows the current user details.so, how can i get the new user's detail without refreshing the page?

CreateQuote component :

import { useMutation } from "@apollo/client";
import React, { useState } from "react";
import { CREATE_QUOTE } from "../gqloperations/mutations";

function CreateQuote() {
  const [quote, setQuote] = useState("");
  const [createQuote, { loading, error, data }] = useMutation(CREATE_QUOTE, {
    refetchQueries: ["getAllQuotes", "getMyProfile"],
  });

  data && console.log(data);

  const handleSubmit = () => {
    createQuote({
      variables: {
        name: quote,
      },
    });
  };

  if (loading) {
    return <h1>loading...</h1>;
  }
  return (
    <div className="container">
      {error && <div className="red card-panel">{error.message}</div>}
      {data && <div className="green card-panel">{data.quote}</div>}
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={quote}
          onChange={(e) => setQuote(e.target.value)}
          placeholder="write your quote"
        />
        <button className="btn green" type="submit" onClick={handleSubmit}>
          create
        </button>
      </form>
    </div>
  );
}

export default CreateQuote;

Login Component :

import React, { useState } from "react";
import { useNavigate } from "react-router";
import { Link } from "react-router-dom";
import { LOGIN_USER } from "../gqloperations/mutations";

export default function Login() {
  const [formData, setFormData] = useState({ email: "", password: "" });
  const [signinUser, { loading, data, error }] = useMutation(LOGIN_USER, {
    refetchQueries: ["getMyProfile"],
    onCompleted(data) {
      localStorage.setItem("token", data.user.token);
      navigate("/");
    },
  });
  const navigate = useNavigate();
  const handleChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    signinUser({
      variables: {
        userSignin: formData,
      },
    });
    setFormData({ email: "", password: "" });
  };
  if (loading) return <h1>Loading</h1>;
  // if (data) {
  //   localStorage.setItem("token", data.user.token);
  //   navigate("/");
  // }
  return (
    <>
      {error && <div className="red card-panel">{error.message}</div>}
      {data && data.signupUser && (
        <div className="green card-panel">
          {data.user.token} login successfully
        </div>
      )}
      <div>
        <h1>Login</h1>
        <form onSubmit={handleSubmit}>
          <input
            type="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
            placeholder="email"
          />
          <input
            type="password"
            name="password"
            value={formData.password}
            onChange={handleChange}
            placeholder="password"
          />
          <Link to="/login">
            <p>Don't have an account ?</p>
          </Link>
          <button type="submit" className="green btn">
            Login
          </button>
        </form>
      </div>
    </>
  );
}

Profile component:

import React, { useEffect } from "react";
import { useQuery } from "@apollo/client";
import { GET_MY_PROFILE } from "../gqloperations/queries";
import { useNavigate } from "react-router";

export default function Profile() {
  const { loading, error, data, refetch } = useQuery(GET_MY_PROFILE);
  useEffect(() => {
    refetch();
  }, [data]);
  const navigate = useNavigate;
  if (!localStorage.getItem("token")) {
    navigate("/login");
  }
  if (loading) return <h1>Loading...</h1>;
  if (error) console.log(error);
  return (
    <div className="container">
      <div className="center-align">
        <img
          style={{ border: "2px solid black", marginTop: "10px" }}
          className="circle"
          src={`https://robohash.org/${data.user.firstName}.png?size=200x200`}
          alt=""
        />
        <h5>
          {data.user.firstName} {data.user.lastname}
        </h5>
        <h5>Email-{data.user.email}</h5>
      </div>
      <h3>Your quotes</h3>
      {data.user.quotes.map((quote) => {
        return (
          <blockquote>
            <h6>{quote.name}</h6>
          </blockquote>
        );
      })}
    </div>
  );
}

Navbar component: (contains Logout button)

import React from "react";
import { useNavigate } from "react-router";
import { Link } from "react-router-dom";

function NavBar() {
  const token = localStorage.getItem("token");
  const navigate = useNavigate();
  return (
    <div>
      <nav>
        <div className="nav-wrapper">
          <Link to="/" className="brand-logo left">
            Quotes
          </Link>
          <ul id="nav-mobile" className="right">
            {token ? (
              <>
                <li>
                  <Link to="/profile">Profile</Link>
                </li>
                <li>
                  <Link to="/create">Create</Link>
                </li>
                <li>
                  <button
                    className="red btn"
                    onClick={() => {
                      localStorage.removeItem("token");
                      navigate("/login");
                    }}
                  >
                    Logout
                  </button>
                </li>
              </>
            ) : (
              <>
                <li>
                  <Link to="/login">Login</Link>
                </li>
                <li>
                  <Link to="/signup">Signup</Link>
                </li>
              </>
            )}
          </ul>
        </div>
      </nav>
    </div>
  );
}

export default NavBar;

Edit : after slothOverlord's answer ,the updates are as below: Navbar component

import React from "react";
import { useNavigate } from "react-router";
import { Link } from "react-router-dom";
import { client } from "../index.js";

function NavBar() {
  const token = localStorage.getItem("token");
  const navigate = useNavigate();
  return (
    <div>
      <nav>
        <div className="nav-wrapper">
          <Link to="/" className="brand-logo left">
            Quotes
          </Link>
          <ul id="nav-mobile" className="right">
            {token ? (
              <>
                <li>
                  <Link to="/profile">Profile</Link>
                </li>
                <li>
                  <Link to="/create">Create</Link>
                </li>
                <li>
                  <button
                    className="red btn"
                    onClick={async() => {
                      localStorage.removeItem("token");
                      await client.resetStore();
                      navigate("/login");
                    }}
                  >
                    Logout
                  </button>
                </li>
              </>
            ) : (
              <>
                <li>
                  <Link to="/login">Login</Link>
                </li>
                <li>
                  <Link to="/signup">Signup</Link>
                </li>
              </>
            )}
          </ul>
        </div>
      </nav>
    </div>
  );
}

export default NavBar;

Login component :

import { useMutation } from "@apollo/client";
import React, { useState } from "react";
import { useNavigate } from "react-router";
import { Link } from "react-router-dom";
import { LOGIN_USER } from "../gqloperations/mutations";

export default function Login() {
  const [formData, setFormData] = useState({ email: "", password: "" });
  const [signinUser, { loading, data, error ,client}] = useMutation(LOGIN_USER, {
    refetchQueries: ["getMyProfile"],
   
    onCompleted(data) {
      localStorage.setItem("token", data.user.token);
      client.clearStore();
      navigate("/");
    },
  });
  const navigate = useNavigate();
  const handleChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    signinUser({
      variables: {
        userSignin: formData,
      },
    });
    setFormData({ email: "", password: "" });
  };
  if (loading) return <h1>Loading</h1>;
  // if (data) {
  //   localStorage.setItem("token", data.user.token);
  //   navigate("/");
  // }
  return (
    <>
      {error && <div className="red card-panel">{error.message}</div>}
      {data && data.signupUser && (
        <div className="green card-panel">
          {data.user.token} login successfully
        </div>
      )}
      <div>
        <h1>Login</h1>
        <form onSubmit={handleSubmit}>
          <input
            type="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
            placeholder="email"
          />
          <input
            type="password"
            name="password"
            value={formData.password}
            onChange={handleChange}
            placeholder="password"
          />
          <Link to="/login">
            <p>Don't have an account ?</p>
          </Link>
          <button type="submit" className="green btn">
            Login
          </button>
        </form>
      </div>
    </>
  );
}

other components are same as above.

1 Answers

You can clear the store of apollo cache. either use client.clearStore() /Reset the store or client.resetStore() /Reset the store and Refetch any active queries

const [signinUser, { loading, data, error, client }] = useMutation(LOGIN_USER, {
    refetchQueries: ["getMyProfile"],
    onCompleted(data) {
      localStorage.setItem("token", data.user.token);
      client.clearStore //Make sure you reset it AFTER you are done adding/clearing tokens
      navigate("/");
    },

I also recommend you to use client.clearStore on your LOGOUT mutation, not on login.

Note that resetStore is async and you should await it. More info at apollo docs: https://www.apollographql.com/docs/react/caching/advanced-topics/

If you are using a normal function, you can import the cache from your Apollo cache (Where you exported it), and clear the store that way.

import {cache} from '../path/to/your/apollo/cache'

//...
           <button
                    className="red btn"
                    onClick={() => {
                      localStorage.removeItem("token");
                      client.resetStore()
                      navigate("/login");
                    }}
                  >
                    Logout
                  </button>
Related