首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >响应上下文,钩子路由器不会在组件挂载上重定向

响应上下文,钩子路由器不会在组件挂载上重定向
EN

Stack Overflow用户
提问于 2019-09-20 18:13:24
回答 2查看 1.7K关注 0票数 1

我试图用CodeSandbox (这里)“复制”我的真实世界项目。我有一个登录表单,当登录时,它使用auth数据设置cookie。当<LoginPage>组件挂载时,它应该检查该cookie,如果存在,它应该重定向回<HomePage>组件。

在我的例子中,它不像预期的那样工作,因为它要等到我在<LoginPage>表单中写东西时才能工作。

根据连接路由器文档navigate()应该作为router <Redirect />组件。

因此,这是项目src文件夹结构:

  • 钢筋混凝土
    • index.js
    • 组件
      • 页面
        • 家庭
          • index.js

代码语言:javascript
复制
        - Login  
            - index.js

代码语言:javascript
复制
- context  
    - Auth  
        - auth.js
        - index.js

代码:

App:src/index.js

代码语言:javascript
复制
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { useRoutes, A, navigate } from "hookrouter";
import { useCookies } from "react-cookie";

import HomePage from "./components/pages/Home";
import LoginPage from "./components/pages/Login";

import AuthContextWrapper from "./context/Auth";

const Logout = () => {
  const [cookies, setCookie, removeCookie] = useCookies(["token"]);
  useEffect(() => {
    console.log("Logout triggered");
    removeCookie("token");
    navigate("/", true);
  }, []);
  return <p>Closing session</p>;
};

const routes = {
  "/": () => <HomePage />,
  "/login": () => <LoginPage />,
  "/logout": () => <Logout />
};

const App = () => {
  const Router = useRoutes(routes);
  return Router ? (
    <AuthContextWrapper>{Router}</AuthContextWrapper>
  ) : (
    <h1>
      Error 404: <A href="/">Go back</A>
    </h1>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

<HomePage />:src/components/pages/Home/index.js

代码语言:javascript
复制
import React, { Fragment, useContext } from "react";
import { A } from "hookrouter";
import AuthContext from "../../../context/Auth/auth";

const HomePage = () => {
  const context = useContext(AuthContext);
  console.log("Home context", context);
  return (
    <Fragment>
      <A href="/login">Login page</A>
      {context.token.length ? <A href="/logout">Logout</A> : ""}
    </Fragment>
  );
};

export default HomePage;

<LoginPage />:src/components/pages/Login/index.js

代码语言:javascript
复制
import React, { useState, useContext, useEffect } from "react";
import AuthContext from "../../../context/Auth/auth";
import { navigate } from "hookrouter";

const LoginPage = () => {
  const context = useContext(AuthContext);
  const [emailState, setEmailState] = useState("");
  const [passwordState, setPasswordState] = useState("");
  const [statusState, setStatusState] = useState({
    color: "black",
    status: ""
  });

  useEffect(() => {
    console.log("Login context:", context);
    if (context.token) {
      navigate("/");
    }
  }, []);

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={emailState}
        onChange={e => setEmailState(e.target.value)}
        placeholder="Email"
      />
      <input
        value={passwordState}
        onChange={e => setPasswordState(e.target.value)}
        placeholder="Password"
        type="password"
      />
      <p style={{ color: statusState.color }}>{statusState.status}</p>
      <button>Login</button>
    </form>
  );

  async function handleSubmit(e) {
    e.preventDefault();
    setStatusState({
      color: "blue",
      status: "Validating"
    });
    await context.login(emailState, passwordState);
    if (context.error) {
      setStatusState({
        color: "red",
        status: context.error
      });
    }
    if (context.token) {
      navigate("/");
    }
  }
};

export default LoginPage;

<AuthContextWrapper />:src/Auth/Auth/index.js

代码语言:javascript
复制
import React, { useEffect } from "react";
import Context from "./auth";
import { useCookies } from "react-cookie";

const AuthContextWrapper = props => {
  const [cookies, setCookie] = useCookies(["token"]);
  const defaultValue = {
    token: "",
    error: "",
    loading: false,
    login: async (email, password) => {
      setTimeout(() => {
        defaultValue.loading = true;
        if (password !== "123") {
          defaultValue.error = "Wrong credentials";
        } else {
          defaultValue.error = "";
          defaultValue.token = "jwtencodedtoken$123";
          setCookie("token", defaultValue.token);
        }
      }, 1000);
      defaultValue.loading = false;
    }
  };
  useEffect(() => {
    if (cookies.token) {
      defaultValue.token = cookies.token;
    }
  });
  return (
    <Context.Provider value={defaultValue}>{props.children}</Context.Provider>
  );
};

export default AuthContextWrapper;

所以我想我的头爆炸了..。这是一个活生生的例子住在CodeSandbox里面。钩子可能有问题(我还在学习它们)。

为什么这不起作用?我做错了什么?如有任何意见,敬请见谅。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-20 19:17:41

好的,我更新了你的代码沙箱这里

更改src/context/Auth/index.js

您的上下文提供程序有点尴尬。如果您尝试使用登录函数直接操作一个对象,那么您将遇到一个糟糕的时刻。如果希望看到更新,将它们绑定到状态,并将它们作为值传递给提供程序。

更改src/components/pages/Login/index.js

这个handleSubmit函数不是异步的,您如何设置这个函数也是有问题的,而不需要保证登录函数。最后,您会在等待时间提前返回,而不是在超时之后返回。

您最好用适当的useEffect来响应useEffect钩子中的上下文更新。这样,只要上下文更新,就可以在此组件中进行必要的更新。

票数 2
EN

Stack Overflow用户

发布于 2019-09-20 19:18:36

这是一个愚蠢的解决方案,请使用@apachuilo的答案。只是把它留在这里供参考,因为我发现添加超时会使它工作起来很有趣。

问题似乎是您的context.token值在登录函数的useEffect钩子中计算为空。如果向您的useEffect函数添加超时,它确实有时间检索上下文值,您的重定向将工作:

代码语言:javascript
复制
useEffect(() => {
  const timer = setTimeout(() => {
    if (context.token) {
      navigate("/");
    }
  }, 100);
  return () => clearTimeout(timer);
}, []);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58033342

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档