我试图用CodeSandbox (这里)“复制”我的真实世界项目。我有一个登录表单,当登录时,它使用auth数据设置cookie。当<LoginPage>组件挂载时,它应该检查该cookie,如果存在,它应该重定向回<HomePage>组件。
在我的例子中,它不像预期的那样工作,因为它要等到我在<LoginPage>表单中写东西时才能工作。
根据连接路由器文档,navigate()应该作为router <Redirect />组件。
因此,这是项目src文件夹结构:
- Login
- index.js
- context
- Auth
- auth.js
- index.js
代码:
App:src/index.js
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
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
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
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里面。钩子可能有问题(我还在学习它们)。
为什么这不起作用?我做错了什么?如有任何意见,敬请见谅。
发布于 2019-09-20 19:17:41
好的,我更新了你的代码沙箱这里。
更改src/context/Auth/index.js
您的上下文提供程序有点尴尬。如果您尝试使用登录函数直接操作一个对象,那么您将遇到一个糟糕的时刻。如果希望看到更新,将它们绑定到状态,并将它们作为值传递给提供程序。
更改src/components/pages/Login/index.js
这个handleSubmit函数不是异步的,您如何设置这个函数也是有问题的,而不需要保证登录函数。最后,您会在等待时间提前返回,而不是在超时之后返回。
您最好用适当的useEffect来响应useEffect钩子中的上下文更新。这样,只要上下文更新,就可以在此组件中进行必要的更新。
发布于 2019-09-20 19:18:36
这是一个愚蠢的解决方案,请使用@apachuilo的答案。只是把它留在这里供参考,因为我发现添加超时会使它工作起来很有趣。
问题似乎是您的context.token值在登录函数的useEffect钩子中计算为空。如果向您的useEffect函数添加超时,它确实有时间检索上下文值,您的重定向将工作:
useEffect(() => {
const timer = setTimeout(() => {
if (context.token) {
navigate("/");
}
}, 100);
return () => clearTimeout(timer);
}, []);https://stackoverflow.com/questions/58033342
复制相似问题