Home > Software design >  How do i save api data that isn't in a state, with the context api?
How do i save api data that isn't in a state, with the context api?

Time:11-13

I need to save a userId and username coming from an API call with the context API.

I need the data, so I can use them globally in my React project, and the API data I need is only send after you successfully log in.

LoginContext.js

import { createContext } from "react";

export const LoginDataContext = createContext(null)

App.js

// React
import { useState, useMemo } from "react";

// React router dom
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";

// Context
import { LoginDataContext } from "./Contexts/LoginContext";

// Pages
import HomePage from "./pages/HomePage";
import NotFound from "./pages/404";
import MailSignup from "./pages/MailSignup";
import AdminLogin from "./pages/LoginAdmin";
import AdminDashboard from "./pages/Dashboard";

function App() {
  const [token, setToken] = useState(null);
  const [user, setUser] = useState(null);

  const userValue = useMemo(() => ({ user, setUser }), [user, setUser]);

  return (
    <div className="App">
      <LoginDataContext.Provider value={userValue}>
        <Router>
          <Routes>
            <Route path="/" element={<HomePage />} />
            <Route path="/EmailReceipt" element={<MailSignup />} />
            <Route path="/Admin" element={<AdminLogin setToken={setToken} />} />
            <Route path="/Dashboard" element={<AdminDashboard token={token}/>} />
            <Route path={"*"} element={<NotFound />} />
          </Routes>
        </Router>
      </LoginDataContext.Provider>
    </div>
  );
}

export default App;

LoginAdmin.js

// React
import { useNavigate } from "react-router-dom";
import { useState, useContext } from "react";
import { Link } from "react-router-dom";

// Axios
import axios from "axios";

// Context
import { LoginDataContext } from "../Contexts/LoginContext";

// Logo
import DyreLogo from "../assets/logo.png";

// Icons
import { HiArrowNarrowLeft } from "react-icons/hi";

const AdminLogin = ({setToken}) =\> {
const \[isLoggingIn, setIsLoggingIn\] = useState(false);
const \[badLogin, setBadLogin\] = useState(false);
const { user, setUser} = useContext(LoginDataContext)

let navigate = useNavigate();

function handleLogin(e) {
e.preventDefault();
setIsLoggingIn(true);
setBadLogin(false);
const form = e.target;
const username = form\[0\].value;
const password = form\[1\].value;

    // console.log(username   ' '   password);
    
    axios
      .post("http://localhost:4000/auth/token", {
        username: username,
        password: password,
      })
      .then((response) => {
        if (response.status === 200) {
          console.log(response.data)
          const userID = response.data.userId
          setToken(response.data.token);
          axios
            .get("http://localhost:4000/api/v1/users/"   userID, {
              headers: { Authorization: `Bearer ${response.data.token}` },
            })
            .then((response) => {
              if (response.status === 200) {
                console.log(response)
                setIsLoggingIn(false);
                navigate("/Dashboard");
              }
            });
        }
      })
      .catch((error) => {
        setIsLoggingIn(false);
        setBadLogin(true);
      });

}
return (
\<div className="flex justify-center items-center flex-col h-screen bg-gray-200"\>
\<img
src={DyreLogo}
alt="Logo of hands holding a dog"
className="w-28 h-28 border-4 border-blue-600 p-2 rounded-full"
/\>
\<form
className="bg-white flex flex-col gap-10 w-\[28rem\] px-28 pb-24 pt-10 mt-10 rounded-md shadow-md"
onSubmit={handleLogin}
\\>
\<div\>
\<h2\>Brugernavn\</h2\>
\<input
className="bg-gray-300 rounded-sm w-full p-2 mt-2 outline-none"
type="text"
/\>
\</div\>
\<div\>
\<h2\>Adgangskode\</h2\>
\<input
className="bg-gray-300 rounded-sm w-full p-2 mt-2 outline-none"
type="password"
/\>
\</div\>
{badLogin && (
\<div className="bg-red-500 text-white text-center visible rounded-sm"\>Brugernavn eller adganskode var forkert\</div\>
)}
\<button className="p-2 px-3 bg-blue-600 rounded-sm text-white w-full"\>
{!isLoggingIn ? "Log ind" : "Logger ind"}
\</button\>
\<Link to="/"\>
\<div className="flex items-center gap-2"\>
\<HiArrowNarrowLeft className="w-5 h-5" /\>
\<p\>Hjem\</p\>
\</div\>
\</Link\>
\</form\>
\</div\>
);
};

export default AdminLogin;

Here you can see the two api calls i am getting from the LoginAdmin.js page:

api call number 1

api call number 2

I have not yet found a way to store the username and userId and i no longer know what to try/do

Please ask if you need more info regarding the question

I have tried saving the username and id dirrectly from the axios response without any luck.

axios
      .post("http://localhost:4000/auth/token", {
        username: username,
        password: password,
      })
      .then((response) => {
        if (response.status === 200) {
          console.log(response.data)
          const userID = response.data.userId
          setToken(response.data.token);
          axios
            .get("http://localhost:4000/api/v1/users/"   userID, {
              headers: { Authorization: `Bearer ${response.data.token}` },
            })
            .then((response) => {
              if (response.status === 200) {
                console.log(response)
                setIsLoggingIn(false);
                navigate("/Dashboard");
              }
            });
        }
      })
      .catch((error) => {
        setIsLoggingIn(false);
        setBadLogin(true);
      });

I have also watched a lot of videos on the topic, to see if they could help me out. I have not found any videos that could explain it, in a situation like mine.

CodePudding user response:

set the user in AdminLogin handleLogin => setUser(user) before redirect

const AdminLogin = ({setToken}) => {

    const [isLoggingIn, setIsLoggingIn] = useState(false);
    const [badLogin, setBadLogin] = useState(false);
    
    const { user, setUser} = useContext(LoginDataContext)
    
    let navigate = useNavigate();
    
    async function handleLogin(e) {

      e.preventDefault();
      setIsLoggingIn(true);
      setBadLogin(false);
      const form = e.target;
      const username = form[0].value;
      const password = form[1].value;
    
        // console.log(username   ' '   password);

        const authResponse = await  axios
                          .post("http://localhost:4000/auth/token", {
                                   username: username,
                                   password: password,
                           });

        if (authResponse.status ===  200) {
             const userID = authResponse.data.userId
             setToken(authResponse.data.token);

              const userResponse = await  axios
                            .get("http://localhost:4000/api/v1/users/"   userID, {
                              headers: { Authorization: `Bearer ${authResponse.data.token}` },
                             })

              const user = userResponse.data.user;
              setUser(user)  // set the user 
              navigate("/Dashboard");

        }
        
        setIsLoggingIn(false);
    
    }

you can keep the token in another HttpContext and pass httpGet, httpPost that pass bearer token to axios instance

and you can move the login function to parent so that AdminLogin is not dependent on axios and has login logic

Hope it helps

CodePudding user response:

maybe you should want to login first, save de token in the localStorage, and then get the user info.

LoginAdmin.js

    const LoginAdmin = () => {
    const [username, setUsername] = useState('')
    const [password, setPassword] = useState('')
    
    function handleSubmit(e) {
    e.preventDefault();
    
    const { data } = await axios

//to do login and get the token
axios.post("http://localhost:4000/auth/token", {
    username: username,
    password: password,
  })
 // set the token in localstorage and after get it in the useEffect in the App function
 localStorage.setItem('token', data)
    
    
    return (
     //i recommend you read the docs if you do not understand the form below
<form onSubmit={handleSubmit}>
      <input type="text" name="username" value={username}   onChange=(e => setUsername(e.target.value) />
    <input type="password" name="password" value={password} onChange=(e => setPassword(e.target.value) />
    <button type="submit">login</button>
</form>
    )}

try adding a useEffect that query the data in every refresh

 function App() {
 //token state deleted
  const [user, setUser] = useState(null);
  
  useEffect(() => {
  //every time the page refreshes make a query and fetch the user and get the token, like this: 

 // here we get the token from localStorage
 const token = localStorage.getItem('token')

// and then fetch the user
 axios
  .get("http://localhost:4000/api/v1/users/"   userID, {
          headers: { Authorization: `Bearer ${token}` },
        })
        .then((response) => {
          if (response.status === 200) {
            console.log(response)
            // setting the user data, then pass it to the provider


            setUser(response.data)
            navigate("/Dashboard");
          }
        });
    }
  })
  .catch((error) => {
    //logginIn deleted, you can validate if the user state is undefined or no and therefore is loggin or no
  });
  }, [])

  return (
    <div className="App">
      // this is the provider!
      <LoginDataContext.Provider value={user} <- here >
        //routes
      </LoginDataContext.Provider>
    </div>
  );
}

export default App;

i hope to help you with this, (my english is bad, im sorry)

  • Related