我有一个React-redux应用程序,我想实现用户登录/注册。对于登录/注册,我使用Django API。我想根据用户登录名创建一些公用和专用路由。
下面是我的代码:
LoginComponent.jsx
import React, { Component } from "react";
import RightPanel from "../AdBanner/RightPanel";
import Panel from "react-bootstrap/es/Panel";
import { connect } from "react-redux";
import * as actions from "../../store/actions/auth";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
};
}
handleUsernameChange = e => {
this.setState({ username: e.target.value });
};
handlePasswordChange = e => {
this.setState({ password: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
this.props.onAuth(
this.state.username,
this.state.password,
"",
"",
"0",
"",
"0"
);
console.log(this.props.isAuthenticated);
if (this.props.isAuthenticated) this.redirectToHome();
else {
this.setState({ errorMsg: "Bad credentials!" });
setTimeout(() => {
this.setState({ errorMsg: "" });
}, 3000);
}
};
redirectToHome = () => <Redirect to={{ pathname: "/" }} />;
render() {
let errorMessage = null;
if (this.props.error) {
errorMessage = <p>{this.props.error}</p>;
}
return (
<section className="body_panel">
<div className="container">
<div className="row">
<div className="col-md-7 padding-lef">
<div className="section-title">
<h3>MySite</h3>
<h1>User Login</h1>
</div>
<div className="inner-content" id="login-panel">
{errorMessage}
<Panel>
<Panel.Body>
<div className="col-sm-12">
<label className="col-sm-4">Email-ID:</label>
<div className="col-sm-8">
<input
type="text"
className="form-control"
onChange={this.handleUsernameChange}
/>
</div>
</div>
<div className="col-sm-12">
<label className="col-sm-4">Password:</label>
<div className="col-sm-8">
<input
type="password"
className="form-control"
onChange={this.handlePasswordChange}
/>
</div>
</div>
<div
className="col-md-12 no-padding"
style={{ marginTop: "20px" }}
>
<div className="col-sm-4" />
<div className="col-sm-8">
<button
type="button"
className="btn"
onClick={this.handleSubmit}
>
Login
</button>
</div>
</div>
</Panel.Body>
</Panel>
</div>
</div>
<RightPanel />
</div>
</div>
</section>
);
}
}
const mapStateToProps = state => {
return {
loading: state.loading,
error: state.error
};
};
const mapDispatchToProps = dispatch => {
return {
onAuth: (
email,
password,
user_android_id,
user_fcm_token,
user_social_flag,
user_name,
user_fb_id
) =>
dispatch(
actions.authLogin(
email,
password,
user_android_id,
user_fcm_token,
user_social_flag,
user_name,
user_fb_id
)
)
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Login);
商店/动作/auth.jsx
import * as actionTypes from "./actionTypes";
import axios from "axios";
export const authStart = () => {
return {
type: actionTypes.AUTH_START
};
};
export const authSuccess = (token, user) => {
return {
type: actionTypes.AUTH_SUCCESS,
token: token,
user: user
};
};
export const authFail = error => {
return {
type: actionTypes.AUTH_FAIL,
error: error
};
};
export const logout = () => {
localStorage.removeItem("user");
localStorage.removeItem("token");
localStorage.removeItem("expirationDate");
return {
type: actionTypes.AUTH_LOGOUT
};
};
//method to check expiration date
export const checkAuthTimeout = expirationTime => {
return dispatch => {
setTimeout(() => {
dispatch(logout);
}, expirationTime * 1000);
};
};
export const authLogin = (
email,
password,
user_android_id,
user_fcm_token,
user_social_flag,
user_name,
user_fb_id
) => {
return dispatch => {
dispatch(authStart());
axios
.post("http://api.mydomain.in/user-login/", {
email: email,
password: password,
user_android_id: user_android_id,
user_fcm_token: user_fcm_token,
user_social_flag: user_social_flag,
user_name: user_name,
user_fb_id: user_fb_id
})
.then(res => {
// console.log(res.data);
if (res.data.result === 1) {
const token = res.data.key;
const user = res.data.user_id;
const expirationDate = new Date(new Date().getTime() + 3600 * 1000); //time duaryion of 1hour
// logic to store user session
// we need to store in something that persist
// so we store in localstorage
localStorage.setItem("token", token);
localStorage.setItem("user", user);
localStorage.setItem("expirationDate", expirationDate);
dispatch(authSuccess(token, user));
dispatch(checkAuthTimeout(3600));
} else {
// console.log("user fail");
dispatch(authFail("User not registered"));
}
})
.catch(err => {
dispatch(authFail(err));
});
};
};
export const authSignup = (
email,
password1,
password2,
username,
phone_no,
user_android_id,
user_fcm_token,
user_social_flag,
user_fb_id,
user_android_app_version
) => {
return dispatch => {
dispatch(authStart());
axios
.post("http://api.mydomain.in/registration/", {
email: email,
password1: password1,
password2: password2,
name: username,
phone_no: phone_no,
user_android_id: user_android_id,
user_fcm_token: user_fcm_token,
user_social_flag: user_social_flag,
user_fb_id: user_fb_id,
user_android_app_version: user_android_app_version
})
.then(res => {
const token = res.data.key;
const user = res.data.user_id;
const expirationDate = new Date(new Date().getTime() + 3600 * 1000); //time duration of 1hour
// logic to store user session
// we need to store in something that persist
// so we store in localstorage
localStorage.setItem("token", token);
localStorage.setItem("user", user);
localStorage.setItem("expirationDate", expirationDate);
dispatch(authSuccess(token, user));
dispatch(checkAuthTimeout(3600));
})
.catch(err => {
dispatch(authFail(err));
});
};
};
export const authCheckState = () => {
return dispatch => {
const token = localStorage.getItem("token");
const user = localStorage.getItem("user");
if (token === undefined && user === undefined) {
dispatch(logout());
} else {
const expirationDate = new Date(localStorage.getItem("expirationDate"));
if (expirationDate <= new Date()) {
dispatch(logout());
} else {
dispatch(authSuccess(token, user));
dispatch(
checkAuthTimeout(
(expirationDate.getTime() - new Date().getTime()) / 1000
)
);
}
}
};
};
App.jsx
import React, { Component } from "react";
import { Router, Route, Switch } from "react-router-dom";
import { Helmet } from "react-helmet";
import Header from "./components/Header_footer/Header";
import Footer from "./components/Header_footer/Footer";
import AdBannerTop from "./components/AdBanner/AdBannerTop";
import AdBannerLeft from "./components/AdBanner/AdBannerLeft";
import Login from "./components/Auth/Login";
import ProtectedPage from "./components/protected/ProtectedPage";
import ReactGA from "react-ga";
import * as actions from "./store/actions/auth";
import { connect } from "react-redux";
import { PrivateRoute } from "./components/PrivateRoute";
import createBrowserHistory from "history/createBrowserHistory";
const history = createBrowserHistory();
ReactGA.initialize("UA-*******-2");
history.listen((location, action) => {
ReactGA.pageview(location.pathname + location.search);
});
class App extends Component {
componentDidMount() {
this.props.onTryAutoSignup();
ReactGA.pageview(window.location.pathname + window.location.search);
}
componentDidUpdate = () =>
ReactGA.pageview(window.location.pathname + window.location.search);
render() {
return (
<Router history={history}>
<React.Fragment>
<Helmet>
<title>My site</title>
<meta name="description" content="my site description" />
</Helmet>
<Header {...this.props} />
<AdBannerTop />
<AdBannerLeft />
<Switch>
<PrivateRoute exact path="/protected-page/" component={ProtectedPage}
/>
<Route exact path="/user-login/" component={Login} />
</Switch>
<Footer />
</React.Fragment>
</Router>
);
}
}
const mapStateToProps = state => {
return {
isAuthenticated: state.token !== null,
user: state.user == null ? null : state.user
};
};
const mapDispatchToProps = dispatch => {
return {
onTryAutoSignup: () => dispatch(actions.authCheckState())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter } from "react-router-dom";
import { createStore, compose, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { Provider } from "react-redux";
import reducer from "./store/reducers/auth";
require("dotenv").config();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
const app = (
<Provider store={store}>
<App />
</Provider>
);
ReactDOM.render(app, document.getElementById("root"));
serviceWorker.unregister();
我的问题:
要创建公用路由和专用路由(仅在用户登录时可访问)。如果用户单击任何私有路由,而不是重定向到登录页面而没有任何消息,则希望该用户收到类似“您需要登录才能访问此消息”的消息。相反,我的私人路线具有如下重定向:
<Route
{...rest}
render={props =>
localStorage.getItem("user") ? (
<Component {...props} />
) : (
<Redirect
to={{ pathname: "/user-login", state: { from: props.location } }}
/>
)
}
/>
另外,成功登录后,用户应重定向到他来自的页面,而不是导航到主页。
请提出一个更好的方法。
谢谢。
答案 0 :(得分:0)
您需要将redux-thunk
与redux
集成。
https://github.com/reduxjs/redux-thunk
不进行重击,就无法处理authCheckState
函数的条件。默认的redux分派将立即解决该问题。