在 React.js 中将用户数据从 useEffect() 保存到 useContext() 之前加载页面

时间:2021-07-18 21:39:16

标签: reactjs use-effect

我在我的项目中使用了 React。在 App.js 文件(入口点)中,它通过这样的 API 获取当前用户。

   
function App() {

    const [user, setUser] = useState(null);
    const [isLoading, setIsLoading] = useState(true);
    const providerValue = useMemo(() => ({user, setUser}), [user, setUser])
    
    useEffect(() => { 
        // IIF b/c u can't use async on useEffect func
        (async () => {
            var headers = new Headers();
            headers.append('Content-Type', 'application/json');
            headers.append('Authorization', Cookies.get("authorization"));
            const response = await fetch('http://localhost:3000/api/users/current', {headers});
            
            const content = await response.json();
            console.log({"from app user": content});
            setUser(content);
        })();
    },[]);

    return (
        <Switch>
            <UserContext.Provider value={providerValue}>
                <Route path="/" exact
                    component={Home}/>
                <Route path="/discover"
                    component={Main}/>
                {/* auth */}
                <Route path="/auth/signup"
                    component={SignUp}/>
                <Route path="/auth/signin"
                    component={SignIn}/>
            </UserContext.Provider>
        </Switch>
    );
}

export default App;

user 和 setUser 然后作为值传递给我的提供者 b/c 我想从其他路由访问用户数据。 当我像这样通过 useContext() 从我的应用程序组件访问用户时...

   export default function DiscoverNavBar(props) {

    {/* useContext to get the user*/}
    const {user} = useContext(UserContext)

    console.log(user);
    const toggleHome = () =>{
        scroll.scrollToTop()
    }
    return <>
        <Navbar collapseOnSelect expand="lg"  bg="dark" variant="dark" sticky="top">
            <Link className="navbar-brand"  onClick={toggleHome}>
                <img alt=""
                    src={logo}
                    width="30"
                    height="30"
                    className="d-inline-block align-top"/>{' '}
                Focal Addis
            </Link>
            <Navbar.Toggle aria-controls="responsive-navbar-nav"/>
            <Navbar.Collapse id="responsive-navbar-nav">
                <Nav className="mr-auto">
                    <Link className="nav-link" to="/directory">Contact us</Link>
                    <LinkS className="nav-link"
                    to="auth"
                    spy={true}
                    smooth={true}
                    exact="true"
                    duration={500} style={{cursor: "pointer"}}>Get Started</LinkS>
                </Nav>
                {props.children}

                {/* here is the problem */}
                <a>{user.email}</a>
               
            </Navbar.Collapse>
        </Navbar>
    </>
}

它不断抛出一个错误,说“试图访问未定义的 .email”。当我注释掉这一行时,它编译成功,甚至用数据记录用户。

我还想在呈现登录和注册页面之前检查用户是否存在。我目前正在尝试这样做,但它也无法在正确的时刻吸引用户。它假设用户不存在。这是登录页面的代码

   export default function SignIn() {

    const ERR_MSSG_STYLES = {
        border: "none",
        color: "red",
        padding: "0",
        width: "100%",
        backgroundColor: "transparent"
    }

    const {user,setUser} = useContext(UserContext)
    
    const history = useHistory()
    var errRef = useRef("")

    useEffect(() => {
        if (user) {
            console.log("already registered");
        }else{
            console.log("nope");
        }
    }, [])

    return (
        <div className="container-fluid">
            <div className="row" style={{height: "100vh"}}>
                <div className="col-md-3 px-5">
                    <Formik 
                        initialValues={{
                            email: '',
                            password: '',
                        }}
                        onSubmit={
                                async (values) => {
                                    const response = await fetch('http://localhost:3000/api/users/login-influencer', {
                                    method: 'POST',
                                    headers: {'Content-Type': 'application/json'},
                                    body: JSON.stringify({
                                        email: values["email"],
                                        password: values["password"],
                                    })
                                })
                                const content = await response.json();
                                if (content["success"] == false) {
                                    errRef.current.value = content["message"]
                                }else{
                                    // change the current user in context
                                    setUser(content)
                                    history.replace("/discover")
                                    Cookies.set('authorization', content["token"], { expires: 7 });
                                }
                            }
                        }
                        >
                        {
                            formik => (
                                <div>
                                    <h1 className="my-4 font-weight-bold-display-4">Focal Addis</h1>
                                    <p>Welcome back, please log in to your account</p>
                                    <input style={ERR_MSSG_STYLES} disabled ref={errRef}/>
                                    <Form>
                                        <TextField label="Email" name="email" type="email"/>
                                        <TextField label="Password" name="password" type="password"/>
                                        <button className="btn btn-danger mt-3 shadow-none" type="submit" style={{width:"100%"}}>Sign In</button>
                                    </Form>
                                    <div className="mt-2 text-red text-center" >
                                        <p>Don't have an account yet?</p>
                                        <Link to="/auth/signup" style={{color: "red"}}>Sign up here.</Link>
                                    </div>
                                </div>
                            )
                        }
                    </Formik>
                </div>

                <div className="col-md-9" style={{backgroundColor: "grey"}}>
                </div>
            </div>
        </div>

    )
}
I am trying to check if any user exists and log a mssg for now but it is only printing "nope"

2 个答案:

答案 0 :(得分:0)

您只需要事先检查,因此电子邮件只会在准备就绪时呈现。

<a>{user?.email}</a> 

也许

 {user?.email &&
   <a>{user.email}</a>    
  }

编辑 1:

您可能需要将整个内容包装在检查中以查看用户是否存在。这是一个总体思路:

  return (
<>
{/*Check here if the user exists or not*/}
  {user ? (
    <Navbar
      collapseOnSelect
      expand="lg"
      bg="dark"
      variant="dark"
      sticky="top"
    >
      <Link className="navbar-brand" onClick={toggleHome}>
        <img
          alt=""
          src={logo}
          width="30"
          height="30"
          className="d-inline-block align-top"
        />{" "}
        Focal Addis
      </Link>
      <Navbar.Toggle aria-controls="responsive-navbar-nav" />
      <Navbar.Collapse id="responsive-navbar-nav">
        <Nav className="mr-auto">
          <Link className="nav-link" to="/directory">
            Contact us
          </Link>
          <LinkS
            className="nav-link"
            to="auth"
            spy={true}
            smooth={true}
            exact="true"
            duration={500}
            style={{ cursor: "pointer" }}
          >
            Get Started
          </LinkS>
        </Nav>
        {props.children}
        {user?.email && <a>{user.email}</a>}
      </Navbar.Collapse>
    </Navbar>
  ) : (
    <h4>User is null</h4>
  )}
</>

);

答案 1 :(得分:0)

API 调用前user 的值是什么,例如第一次渲染? 值为空,无法访问 null.email。 useEffect 和 API 调用只会在此之后发生。

为用户提供默认值

const [user, setUser] = useState({});

并检查

useEffect(() => {
    if (user?.email) {
        console.log("already registered");
    }else{
        console.log("nope");
    }
}, [])