如何在登录后重定向路由器
介绍
随着 Redux 和 React 的流行度与日俱增,给予它们应有的关注是理所当然的。React 使用 Redux 的状态来维护整个应用程序的状态。状态的目的是让您的应用程序状态与 Redux 存储保持同步。
在本指南中,我们将学习如何在成功登录后重定向用户。通常,当我们构建 Web 应用程序时,要求用户必须登录才能使用该应用程序。在这种情况下,我们需要照顾用户的身份并在应用程序状态下管理他的身份验证令牌,并将用户重定向到受保护的路由。
为了设计此演示的样式,我将使用material-ui。请运行以下命令将其添加到您的依赖项中。
npm i @material-ui/core @material-ui/lab
请注意,本指南假设您对现代 ES6 语法有一定的了解。
登录表单
登录表单有两个字段:Email和Password。当用户单击“提交”按钮时,我们将分派一个登录操作,其类型为LOGIN,有效负载为表单值。为了管理组件中的状态,我使用了 React hooks,它现在是管理功能组件中状态的默认方法。
import React, { useState } from "react";
import { TextField, Typography, Button } from "@material-ui/core";
import { connect } from "react-redux";
import { login } from "../actions/auth";
import MuiAlert from "@material-ui/lab/Alert";
function Alert(props) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
export default connect(null, { login })(props => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const submitForm = () => {
if (email === "" || password === "") {
setError("Fields are required");
return;
}
props.login({ email, password });
};
return (
<form>
<Typography variant="h5" style={{ marginBottom: 8 }}>
Login
</Typography>
<TextField
label="Email"
variant="outlined"
fullWidth
className="form-input"
value={email}
onChange={e => setEmail(e.target.value)}
/>
<TextField
label="Password"
variant="outlined"
fullWidth
className="form-input"
type="password"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<Button
variant="contained"
color="primary"
fullWidth
className="form-input"
size="large"
onClick={submitForm}
>
Login
</Button>
{error && (
<Alert severity="error" onClick={() => setError(null)}>
{props.error || error}
</Alert>
)}
</form>
);
});
操作和中间件
与上一个指南一样,我们将使用中间件来处理网络请求,以将登录详细信息发送到我们的服务器。如果您不熟悉 Redux 中的中间件,请查看其他指南。
身份验证
export const LOGIN = "LOGIN";
export const LOGOUT = "LOGOUT";
export const login = user => {
return {
type: LOGIN,
payload: user
};
};
export const logout = () => {
return {
type: LOGOUT
};
};
当LOGIN操作被调度时,我们将在中间件中捕获该操作并调度 API_REQUEST操作以及登录表单值数据。如果请求成功,我们将调度API_SUCCESS操作,如果出现错误,我们将调度API_ERROR操作。
应用程序.js
import { apiRequest } from "../actions/api";
import { LOGIN } from "../actions/auth";
const SERVER_URL = `https://61m46.sse.codesandbox.io`;
export const appMiddleware = () => next => action => {
next(action);
switch (action.type) {
case LOGIN: {
next(
apiRequest({
url: `${SERVER_URL}/login`,
method: "POST",
data: action.payload
})
);
break;
}
default:
break;
}
};
Reducer 函数
在 Reducer 函数中,我们将设置服务器发送的用户AUTH令牌。在实际应用中,出于安全原因,令牌会保存在 Cookie 中,但为了简单起见,我们将把它存储在本地存储中。在设置默认状态时,我们会检查本地存储中是否存在用户令牌。
import { SET_LOADER } from "./actions/ui";
import { API_SUCCESS, API_ERROR } from "./actions/api";
import { LOGOUT } from "./actions/auth";
export default (
state = {
isAuthUser: !!localStorage.getItem("user"),
user: JSON.parse(localStorage.getItem("user")) || {},
isLoading: false,
error: null
},
action
) => {
switch (action.type) {
case API_SUCCESS:
localStorage.setItem("user", JSON.stringify(action.payload.user));
return { ...state, isAuthUser: true, user: action.payload.user };
case API_ERROR:
return { ...state, error: action.payload };
case SET_LOADER:
return { ...state, isLoading: action.payload };
case LOGOUT:
localStorage.removeItem("user");
return { ...state, isAuthUser: false, user: {} };
default:
return state;
}
};
HOC 用于身份验证
为了跨页面验证用户身份,我们需要创建一个高阶组件 (HOC) 来包装<Router />组件。您可能会想,为什么我们必须在每个页面上验证用户身份?嗯,那是因为在单页应用中,我们需要在客户端维护用户的会话。
认证路由有两种,一种是访客路由,只有访客用户才能访问,比如登录页面或者注册页面;第二种是私有路由,只有认证过的用户才能访问。
如果用户未通过身份验证,我们将重定向到索引页;否则,我们将重定向到主页。
import React from "react";
import { connect } from "react-redux";
import { Redirect, Route } from "react-router";
const AuthRoute = props => {
const { isAuthUser, type } = props;
if (type === "guest" && isAuthUser) return <Redirect to="/home" />;
else if (type === "private" && !isAuthUser) return <Redirect to="/" />;
return <Route {...props} />;
};
const mapStateToProps = ({ isAuthUser }) => ({
isAuthUser
});
export default connect(mapStateToProps)(AuthRoute);
使用组件
在<App />组件中,我们将定义应用程序中的所有路由。我们将使用上一节中创建的<AuthRoute />组件来指定路由的类型,无论是私有路由还是访客路由。
export default function App() {
return (
<Provider store={store}>
<Router>
<NavBar />
<div className="container">
<Switch>
<AuthRoute path="/login" type="guest">
<LoginPage />
</AuthRoute>
<AuthRoute path="/home" render={HomePage} type="private" />
<AuthRoute path="/my-account" type="private">
<MyAccount />
</AuthRoute>
<Route path="/" render={IndexPage} />
</Switch>
</div>
</Router>
</Provider>
);
}
完整源代码
index.js
index.js将成为我们 Web 应用程序的入口文件。在这里,我们将根组件挂载到一个元素,即id 为root的<div>。
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
App.js
在App.js文件中,我们定义了主组件或根组件,即<App />组件。我们将使用react-redux库将所有子组件包装在<Provider />组件中,以使全局 redux 存储在整个应用程序中可用。
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "./app.css";
import { Provider } from "react-redux";
import { applyMiddleware } from "redux";
import reducer from "./reducer";
import { createStore } from "redux";
import NavBar from "./components/Nav";
import { Typography, Divider } from "@material-ui/core";
import AuthRoute from "./components/AuthRoute";
import HomePage from "./pages/HomePage";
import <span c免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!

请先 登录后发表评论 ~