0

I'm trying to update the UserContext through form inputs but the value of the context remains null and doesn't shows the Logout button. setUser doesn't change username and password values, it's initialized to null only. But if I remove the form part and only keep the button code with static value of context, it works fine. Please help.

UserContext.js

import { createContext } from "react";
export const UserContext = createContext(null);

Login.js

export const login = async (a,b) => {
    return {
      username: a,
      password: b
    };
  };

index.js

import React, { useContext,createRef } from 'react'
import { UserContext } from './UserContext'
import { login } from './Login'
let u = createRef();
let p = createRef();

export default function Index() {
    const { user, setUser } = useContext(UserContext);

const handleSubmit=e=>{
    let uid=u.current.value;
    let pwd=p.current.value;
    async () => {
        const user = await login(uid,pwd)       
        setUser(user);
    }
    console.log(user)
}

    const printValues= e =>{
            let uid=u.current.value;
    let pwd=p.current.value;
        e.preventDefault();
    
        console.log(uid,pwd)
    }
    return (
        <div>
            HOME!

            <pre>{JSON.stringify(user, null, 2)}</pre>
            {user ? (    


                <button
                    onClick={() => {
                        // call logout
                        setUser(null);
                    }}
                >
                    logout
                </button>
            ) : (

                <form onSubmit={handleSubmit}>
        <label>
          Username:
          <input
          ref={u}
             name="username"
            onChange={printValues}
          />
        </label>
        <br />
        <label>
          Password:
          <input
          ref={p}
            name="password"
            onChange={printValues}
          />
        </label>
        <br />
        <button>Login</button>
      </form>

                )}
        </div>
    )
}
minsuga
  • 321
  • 3
  • 11

1 Answers1

1

This is how I actually handle login using context API - maybe these examples can help you. Also, check this little tutorial - I'm studying too

import { createContext, useState, useEffect, ReactNode } from "react";


const AuthContext = createContext({});

export function AuthProvider({ children }) {
  const [token, setToken] = useState(undefined);
  const [user, setUser] = useState(undefined);
  const [signed, setSigned] = useStatefalse);
  const [loading, setLoading] = useState(true);
  const [useEffectHandle, TriggerUseEffect] = useState(false);


  const signIn = async (received, SignType) => {
    try {
      //Here is my API CALL
      const RequestResponse = await api.post(
        "/auth/" + SignType + "/login",
        received
      );
      const token: string = RequestResponse.data.token;
      const user = JSON.stringify(RequestResponse.data.user);
      setUser(RequestResponse.data.user);
      setToken(token);
      setSigned(true);
      TriggerUseEffect(true);
      sessionStorage.setItem("@odontoeasy:token", token);
      sessionStorage.setItem("@odontoeasy:user", user);
    } catch (error) {
      if (error.response) {
        // Request made and server responded
        console.log({
          response: {
            status: error.response.status,
            data: error.response.data,
            headers: error.response.headers,
          },
        });
      } else if (error.request) {
        // The request was made but no response was received
        console.log(error.request);
      } else {
        // Something happened in setting up the request that triggered an Error
        console.log("Error", error.message);
      }
    }
  };

  const signOut = async () => {
    sessionStorage.clear();
    setUser(undefined);
    setSigned(false);
  };

  const AuthContextValues = {
    loading: loading,
    signIn: signIn,
    signOut: signOut,
    signed: signed,
    token: token,
    user: user,
  };

  return (
    <AuthContext.Provider value={AuthContextValues}>
      {children}
    </AuthContext.Provider>
  );
}

export default AuthContext;

And my Login FORM :

import { SyntheticEvent, FC, useContext, useState } from "react";
import { FiUser, FiKey } from "react-icons/fi";
import { Link } from "react-router-dom";

import Input from "@material-ui/core/Input";

import { Clinic, Dentist, Employer } from "../../@types";
import AuthContext, { ReqBody } from "../../contexts/auth";
import "./styles.css";
import { translate } from "../../locales";
import { Button, Form, LoadingIcon, Holder, RegisterLink } from "./styles";

const LoginForm = ({ type }) => {
  const { signIn, loading } = useContext(AuthContext);
  const [messages, setMessages] = useState("");
  const [registered_id, setClinicId] = useState("");
  const [dentist_id, setDentistId] = useState("");
  const [employee_id, setEmployeeId] = useState("");
  const [password, setPassword] = useState("");
  const [access_key, setAccessKey] = useState("");

  async function handleLogin(event) {
    try {
      event.preventDefault();
      const clinicData = { registered_id, password, access_key };
      const dentistData = { dentist_id, password, access_key };
      const employeeData = { employee_id, password, access_key };
      if (type === 0) {
        signIn(clinicData, "admin");
      } else if (type === 1) {
        signIn(dentistData, "dentist");
      } else if (type === 2) {
        signIn(employeeData, "employee");
      }
    } catch (error) {
      console.log(error);
    }
  }

  return (
    <Form onSubmit={handleLogin}>
      <Holder>
        <div className="input_block">
          <div className="iconContainer">
            <FiUser size={25} color={"#64B5F6"} />
          </div>
          {type === 0 && (
            <Input
              required
              type="text"
              placeholder={translate("clinicID")}
              name="clinic_id"
              value={registered_id}
              onChange={(event) => setClinicId(event.target.value)}
            />
          )}
          {type === 1 && (
            <Input
              required
              type="text"
              placeholder={translate("ID")}
              name="dentist_id"
              value={dentist_id}
              onChange={(event) => setDentistId(event.target.value)}
            />
          )}
          {type === 2 && (
            <Input
              required
              type="text"
              placeholder={translate("ID")}
              name="employee_id"
              value={employee_id}
              onChange={(event) => setEmployeeId(event.target.value)}
            />
          )}
        </div>
        <div className="input_block">
          <div className="iconContainer">
            <FiKey size={25} color={"#64B5F6"} />
          </div>
          <Input
            required
            title="Six or more characters"
            type="password"
            placeholder={translate("password")}
            name="password"
            value={password}
            onChange={(event) => setPassword(event.target.value)}
          />
        </div>
        {loading ? (
          <Button>
            <LoadingIcon />
          </Button>
        ) : (
          <Button type="submit">{translate("enter")}</Button>
        )}
        <RegisterLink>
          <Link to={"/register"}>{translate("register_link")}</Link>
        </RegisterLink>
      </Holder>
    </Form>
  );
};

export default LoginForm;
  • thank you for the wonderful tutorial, it helped me understand the Context concept better. I'll try to work to merge it with async and see. – minsuga Jan 12 '21 at 19:06