【问题标题】:useContext in reactJS with custom hook leading to undefined objectreactJS中的useContext带有导致未定义对象的自定义钩子
【发布时间】:2021-06-23 02:29:29
【问题描述】:

我正在尝试在 React 中设置一个上下文来处理用户信息,一旦用户登录到系统就会调用这些信息。但是,我一开始就无法设置用户。

事实上,用户将输入他们的登录信息,并从下拉列表中选择一个角色。然后 API 根据登录信息返回结果。我正在尝试根据该结果更新用户上下文,但是当我尝试使用 useUserUpdate 对其进行设置时,UserContext 中的用户值最终只是未定义?我在这里做错了什么?

我尝试制作自定义挂钩 useUserUpdate 来处理用户状态的操作,但它不起作用,我很迷茫。我认为这就是问题所在,因为我到处都有 console.log 并且已经看到当调用这个钩子时用户变得未定义。任何可以提供的帮助将不胜感激。

App.js

import React from "react";
import { useUser } from "./contexts";
import { UserContextProvider } from "./contexts";

//import page components
import LoginForm from "./sharedComponents/LoginForm";
import WorkflowTemplate from "./workflows/WorkflowTemplate";
import "./App.css";

function App() {
    const user = useUser();

    return (
        <UserContextProvider>
            <div className="App">
                {user != null ? <WorkflowTemplate /> : <LoginForm />}
            </div>
        </UserContextProvider>
    );
}

export default App;


contexts.js

import React, { createContext, useState, useContext } from "react";
import Cookies from "universal-cookie";

const UserContext = createContext();
const UpdateUserContext = createContext();

const Cookie = new Cookies();

export const useUser = () => {
    return useContext(UserContext);
};

export const useUserUpdate = () => {
    return useContext(UpdateUserContext);
};

export const UserContextProvider = ({ children }) => {
    const [user, setUser] = useState({
        email: "test",
        name: "",
        id: "",
        role: "",
    });
    console.log(user);

    const updateUser = ({ user }) => {
        setUser({ user });
        console.log("user passed to context prov");
        console.log(user);
    };

    return (
        <UserContext.Provider value={user}>
            <UpdateUserContext.Provider value={updateUser}>
                {children}
            </UpdateUserContext.Provider>
        </UserContext.Provider>
    );
};

LoginForm.js

import React, { useState, useEffect } from "react";
import {
    i_sAccessToken,
    i_sGetLoggedInUser,
    i_sGETOrgs,
} from "../publicFunctions/identity_serviceAPI";
import { useUser, useUserUpdate } from "../contexts";
import Cookies from "universal-cookie";
import "../App.css";

function LoginForm() {
    const Cookie = new Cookies();
    const user = useUser();
    const userUpdate = useUserUpdate();
    const [details, setDetails] = useState({
        email: "",
        role: "",
        password: "",
    });
    const submitHandler = (event) => {
        event.preventDefault();
        Login(details);
        setDetails({ email: "", password: "", role: "" });
    };

    const Login = (details) => {
        if (details.email === "") return alert("No email entered");
        if (details.password === "") return alert("No password entered");
        if (details.role === "") return alert("Please select a role");

        //call API here to check username and save JWT
        i_sAccessToken(details).then((result) => {
            if (result.detail === "Incorrect email or password") {
                alert("Incorrect email or password");
            } else {
                //if result does not return error set cookie
                Cookie.set("JWT", result.access_token);
                //get USER info from API
                i_sGetLoggedInUser().then((result) => {
                    userUpdate({
                        ...user,
                        email: result.email,
                        name: result.name,
                        id: result.id,
                        role: details.role,
                    });
                });
            }
        });
    };

    return (
        <form onSubmit={submitHandler}>
            <div className="form-inner">
                <h2>Login</h2>
                {/*{error != "" ? <div className="error">{error} </div> : ""}*/}

                <div className="form-group">
                    <label htmlFor="email">Email: </label>
                    <input
                        type="text"
                        name="name"
                        id="name"
                        onChange={(event) =>
                            setDetails({ ...details, email: event.target.value })
                        }
                        value={details.email}
                    />
                </div>
                <div className="form-group">
                    <label htmlFor="password">Password: </label>
                    <input
                        type="password"
                        password="password"
                        id="password"
                        onChange={(event) =>
                            setDetails({ ...details, password: event.target.value })
                        }
                        value={details.password}
                    />
                </div>
                <div>
                    <label htmlFor="role">Enter Role: </label>
                    <select
                        onChange={(event) =>
                            setDetails({ ...details, role: event.target.value })
                        }
                        value={details.role}
                    >
                        <option value="">Select Role</option>
                        <option value="Analyst">Analyst</option>
                        <option value="Manager">Manager</option>
                        <option value="Sample admin">Sample admin</option>
                        <option value="Developer">Developer</option>
                    </select>
                </div>
                <input type="submit" value="LOGIN" />
            </div>
        </form>
    );
}

export default LoginForm;




【问题讨论】:

    标签: reactjs react-hooks undefined use-state use-context


    【解决方案1】:

    您将处理程序定义为将对象作为包含用户的参数,但在调用userUpdate 函数时,您直接传递了user

    // this function expects an object that has a property user
    const updateUser = ({ user }) => {
        // this will again set an object in the state that contains the user rather than the user itself
        setUser({ user });
        // ....
    };
    
    // here you pass the user directly
    userUpdate({
        ...user,
        email: result.email,
        name: result.name,
        id: result.id,
        role: details.role,
    });
    

    此外,没有理由为用户和更新程序函数设置两个单独的上下文。你可以在同一个上下文中同时拥有 user 和 updater 函数。

    const UserContext = createContext();
    
    const initialUser = {
        email: "test",
        name: "",
        id: "",
        role: "",
    }
    
    export const useUser = () => useContext(UserContext);
    
    export const UserContextProvider = ({ children }) => {
        const userState = useState(initialUser);
    
        return (
            <UserContext.Provider value={userState}>  
                {children}
            </UserContext.Provider>
        );
    };
    

    然后您可以像这样简单地使用它:

    const [user, updateUser] = useUser();
    

    【讨论】:

    • 感谢您的帮助,我从函数参数中删除了 {},现在它正在工作:) 将尝试使用您的其他建议清理上下文。谢谢!
    • @Greg 很高兴它对您有所帮助。如果您认为它解决了您的问题,请投票和/或将其标记为已接受的答案。
    【解决方案2】:

    useUser 必须调用 UserContextProvider 所在位置的子代

    例如:

    <UserContextProvider>
      <User />
    </UserContextProvider>
    

    Users.js

    function Users() {
        const user = useUser();
    
        return (
             <div className="App">
                    {user != null ? <WorkflowTemplate /> : <LoginForm />}
                </div>
        );
    }
    

    【讨论】:

      猜你喜欢
      • 2022-01-24
      • 2020-01-23
      • 1970-01-01
      • 1970-01-01
      • 2020-08-04
      • 2020-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多