Search code examples
javascriptreactjsexpressmern

i am unable to get the user id via context api after login page


i created a login page which will post request on the /auth/login route in my backend express server after my backend server verifies the user the page will navigate on this route /auth/profile/${userId} using useNavigate, this route will get the user information from the database the URL is showing that I am getting the id from backend but when I am using context API to fetch user details it is showing that the userId is undefined in the route how I get the user id first to get the request in my context API

loginUser function

const loginUser = async (e) => {
    e.preventDefault();
    const { email, password } = login;
    try {
      const response = await axios.post('/auth/login', {
        email,
        password,
      });
      const { userId } = response.data;
      setUserId(userId);
       console.log(`hi i am login page the user id is ${userId}`);
      if (login.error) {
        toast.error(login.error);
      } else {
        setLogin({});
        toast.success('Login Successful. Welcome!');

        // Use the updated userId here
        navigate(`/auth/profile/${userId}`);
      }
    } catch (error) {
      console.error(error);
    }
  };

contextApi

  import React, {useState, useEffect} from "react";
import axios from "axios"
import { createContext } from "react";

export const UserContext = createContext({});

export function UseContextProvider({children , userId}) {
    const [user, setUser] = useState(null);


    useEffect(() => {
        const fetchUserDetails = async () => {
            try {
                const response = await axios.get(`/auth/profile/${userId}`)
                setUser(response.data);
            } catch (error) {
                console.error("Error fetching user details:", error);
            }
        }
        fetchUserDetails();
    }, [userId])
    return (
        <UserContext.Provider value={{ user, setUser }}>
          {children}
        </UserContext.Provider>
      );
};

Backend -- loginUser Function

 const loginUser = async (req, res) => {
    try {
        const { email, password } = req.body;
        if (!email || !password) {
            return res.json({ message: 'Please enter all the details' })
        }
        //check if the user already exist or not
        const userExist = await User.findOne({ email: req.body.email });
        if (!userExist) {
            return res.json({ message: 'Wrong credentials' })
        }
        // check password match
        const isPasswordMatched = await comparePassword(password, userExist.password);
        if (!isPasswordMatched) {
            return res.json({ message: 'Wrong credentials pass' });
        }
        const token = await jwt.sign({ id: userExist._id }, process.env.JWT_SECRET, {
            expiresIn: process.env.JWT_EXPIRE,
        })
        return res
            .cookie('token', token, { httpOnly: true })
            .json({ success: true, message: 'LoggedIn Successfully', userId: userExist._id });
    } catch (error) {
        return res.json({ error: error });
    }
};

getProfile function

    const getProfile = async (req, res) => {
    try {
        const user = await User.findOne();
        if (!user) {
            return res.json({ message: 'No user found' })
        }
        return res.json({ user: user})
    } catch (error) {
        return res.json({ error: error });
    }
};

isAuthenticated Middleware

    const isAuthenticated = async (req, res, next) => {
    try {
        const token = req.headers.authorization;

        if (!token) {
            return res.status(401).json({ message: 'Unauthorized: No token provided' });
        }

        jwt.verify(token, process.env.JWT_SECRET, async (err, decoded) => {
            if (err) {
                // Handle token verification failure
                return res.status(401).json({ message: 'Unauthorized: Invalid token' });
            }

            // Check if the token has expired
            if (decoded.exp < Date.now() / 1000) {
                return res.status(401).json({ message: 'Unauthorized: Token has expired' });
            }

            // Retrieve user information from the database using the user ID from the token
            req.user = await User.findById(decoded.id);
            next();
        });
    } catch (error) {
        // Handle other errors
        return next(error);
    }
};

Solution

  • Maintain a state for userId to initaite the useEffect hook.

    //context.jsx
    export function UseContextProvider({children}) {
    const [user, setUser] = useState(null);
    const [userId, setUserId] = useState(null);
       useEffect(() => {
          const fetchUserDetails = async () => {
             try {
               const response = await axios.get(`/auth/profile/${userId}`)
               setUser(response.data);
             } catch (error) {
               console.error("Error fetching user details:", error);
             }
          }
          fetchUserDetails();
        }, [userId])
        return (
            //pass the setuserId state and if needed also pass the userId
            <UserContext.Provider value={{ user, userId, setUser, setUserId }}> 
              {children}
            </UserContext.Provider>
        );
    };
    

    Remove the separate state that is maintained in the LoginForm.jsx, instead utilize the state from the context.jsx.

    //LoginForm.jsx
    const Loginform = () => {
        const navigate = useNavigate();
        //remove this state
        const { setUserId } = React.useContext(UserContext);
        const [login, setLogin] = useState({
            email: '',
            password: '',
        })
    
        const loginUser = async (e) => {
            e.preventDefault();
            const { email, password } = login;
            try {
              const response = await axios.post('/auth/login', {
                email,
                password,
              });
              const { userId } = response.data;
              setUserId(userId); //setUserId from context.jsx
              if (login.error) {
                toast.error(login.error);
              } else {
                setLogin({});
                toast.success('Login Successful. Welcome!');
                navigate(`/auth/profile/${userId}`);
              }
            } catch (error) {
              console.error(error);
            }
          };
    }
    

    This will update the userId and trigger the useEffect in the context Provider to fetch the user details.