Reactjs 成功登录后响应路由器未重定向
我用的是React路由器4,Redux,Redux传奇,Redux表单。我创建了一条私人路线,它有一个道具授权。登录成功,但未重定向。感谢您的帮助 login.jsReactjs 成功登录后响应路由器未重定向,reactjs,react-redux,redux-form,react-router-v4,Reactjs,React Redux,Redux Form,React Router V4,我用的是React路由器4,Redux,Redux传奇,Redux表单。我创建了一条私人路线,它有一个道具授权。登录成功,但未重定向。感谢您的帮助 login.js import React, {Component} from 'react'; import {connect} from 'react-redux'; import {reduxForm, Field} from 'redux-form'; import PropTypes from 'prop-t
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {reduxForm, Field} from 'redux-form';
import PropTypes from 'prop-types';
import { TextField } from 'redux-form-material-ui';
import Checkbox from 'material-ui/Checkbox';
import RaisedButton from 'material-ui/RaisedButton';
import loginRequest from '../../actions/loginActions';
//field validations
import required from '../form-validation/required';
import email from '../form-validation/email'
class Login extends Component {
// Pass the correct proptypes in for validation
static propTypes = {
handleSubmit: PropTypes.func,
loginRequest: PropTypes.func,
pristine: PropTypes.bool,
login: PropTypes.shape({
requesting: PropTypes.bool,
successful: PropTypes.bool,
messages: PropTypes.array,
errors: PropTypes.array,
}),
}
componentDidMount() {
this.refs.name // the Field
.getRenderedComponent() // on Field, returns ReduxFormMaterialUITextField
.getRenderedComponent() // on ReduxFormMaterialUITextField, returns TextField
.focus(); // on TextField
}
// Remember, Redux Form passes the form values to our handler
// In this case it will be an object with `email` and `password`
submit = (values) => {
this.props.loginRequest(values)
}
render (){
const {
handleSubmit,
pristine,
login: {
requesting,
successful,
messages,
errors,
}
} = this.props
return (
<div>
<form className="loginForm" onSubmit={handleSubmit(this.submit)}>
<div className="login-wrapper">
<div className="login-fields">
<h3>Login <a href="">Forgot Password?</a></h3>
<Field
name="email"
component={TextField}
floatingLabelText="Username or Email"
validate={[required, email]}
fullWidth={true}
ref="name"
withRef
/>
<Field
name="password"
component={TextField}
type="password"
floatingLabelText="Password"
validate={required}
fullWidth={true}
ref="name"
withRef
/>
<div className="pt20">
<Checkbox
label="Remember Me"
/>
</div>
<div className="pt20">
<RaisedButton type="submit" label="Log In" primary={true} fullWidth={true} disabled={pristine || requesting}/>
</div>
</div>
</div>
</form>
</div>
);
}
}
// Grab only the piece of state we need
const mapStateToProps = state => ({
login: state.login,
})
// make Redux state piece of `login` and our action `loginRequest`
// available in this.props within our component
const connected = connect(mapStateToProps, { loginRequest })(Login)
const LoginForm = reduxForm({
form: 'loginForm',
})(connected)
export default LoginForm;
loginSagas.js
import { take, fork, cancel, call, put, cancelled } from 'redux-saga/effects'
// Helper for api errors
import { handleApiErrors } from '../lib/api-errors'
import history from '../history'
// Our login constants
import {
LOGIN_REQUESTING,
LOGIN_SUCCESS,
LOGIN_ERROR,
} from '../constants/loginConstants'
// So that we can modify our Client piece of state
import {
setClient,
unsetClient,
} from '../client/actions'
import {
CLIENT_UNSET,
} from '../client/constants'
const loginUrl = `${process.env.REACT_APP_API_URL}${process.env.REACT_APP_API_AUTHENTICATE}`
function loginApi (email, password) {
return fetch(loginUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
})
.then(handleApiErrors)
.then(response => response.json())
.then(json => json)
.catch((error) => { throw error })
}
function* logout () {
// dispatches the CLIENT_UNSET action
yield put(unsetClient())
// remove our token
localStorage.removeItem('token')
// redirect to the /login screen
// browserHistory.push('/login')
yield call(history.push, '/login');
}
function* loginFlow (email, password) {
let token
try {
// try to call to our loginApi() function. Redux Saga
// will pause here until we either are successful or
// receive an error
let response = yield call(loginApi, email, password)
token = response.data.token
// inform Redux to set our client token, this is non blocking so...
yield put(setClient(token))
// .. also inform redux that our login was successful
yield put({ type: LOGIN_SUCCESS })
// set a stringified version of our token to localstorage on our domain
localStorage.setItem('token', JSON.stringify(token))
// redirect them to WIDGETS!
// browserHistory.push('/widgets')
yield call(history.push, '/mail-confirmation');
} catch (error) {
// error? send it to redux
yield put({ type: LOGIN_ERROR, error })
} finally {
// No matter what, if our `forked` `task` was cancelled
// we will then just redirect them to login
if (yield cancelled()) {
// browserHistory.push('/login')
yield call(history.push, '/login');
}
}
// return the token for health and wealth
return token
}
// Our watcher (saga). It will watch for many things.
function* loginWatcher () {
// Generators halt execution until their next step is ready/occurring
// So it's not like this loop is firing in the background 1000/sec
// Instead, it says, "okay, true === true", and hits the first step...
while (true) {
//
// ... and in this first it sees a yield statement with `take` which
// pauses the loop. It will sit here and WAIT for this action.
//
// yield take(ACTION) just says, when our generator sees the ACTION
// it will pull from that ACTION's payload that we send up, its
// email and password. ONLY when this happens will the loop move
// forward...
const { email, password } = yield take(LOGIN_REQUESTING)
// ... and pass the email and password to our loginFlow() function.
// The fork() method spins up another "process" that will deal with
// handling the loginFlow's execution in the background!
// Think, "fork another process".
//
// It also passes back to us, a reference to this forked task
// which is stored in our const task here. We can use this to manage
// the task.
//
// However, fork() does not block our loop. It's in the background
// therefore as soon as our loop executes this it mores forward...
const task = yield fork(loginFlow, email, password)
// ... and begins looking for either CLIENT_UNSET or LOGIN_ERROR!
// That's right, it gets to here and stops and begins watching
// for these tasks only. Why would it watch for login any more?
// During the life cycle of this generator, the user will login once
// and all we need to watch for is either logging out, or a login
// error. The moment it does grab either of these though it will
// once again move forward...
const action = yield take([CLIENT_UNSET, LOGIN_ERROR])
// ... if, for whatever reason, we decide to logout during this
// cancel the current action. i.e. the user is being logged
// in, they get impatient and start hammering the logout button.
// this would result in the above statement seeing the CLIENT_UNSET
// action, and down here, knowing that we should cancel the
// forked `task` that was trying to log them in. It will do so
// and move forward...
if (action.type === CLIENT_UNSET) yield cancel(task)
// ... finally we'll just log them out. This will unset the client
// access token ... -> follow this back up to the top of the while loop
yield call(logout)
}
}
export default loginWatcher
RouteComponent.js
import React, {Component} from 'react';
import {Route, Switch, withRouter } from 'react-router-dom';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import Home from '../pages/home.js';
import LoginPage from '../pages/login.js';
import RegisterPage from '../pages/register.js';
import ForgotPasswordPage from '../pages/forgotPassword.js';
import MailConfirmPage from '../pages/mailConfirm.js';
import Page404 from '../pages/page404.js';
import PrivateRoute from './privateRoute.js'
class RoutesComponent extends Component {
render() {
return (
<div>
<Switch>
<PrivateRoute exact authed="{this.props.authed}" path="/" component={Home}/>
<PrivateRoute path="/mail-confirmation" authed="{this.props.authed}" component={MailConfirmPage}/>
<Route path="/login" component={LoginPage}/>
<Route path="/register" component={RegisterPage}/>
<Route path="/forgot-password" component={ForgotPasswordPage}/>
<Route path="/404" component={Page404}/>
</Switch>
</div>
);
}
}
function mapStateToProps (state) {
return {
authed : state.login.successful
}
}
export default withRouter(connect(mapStateToProps)(RoutesComponent));
import React,{Component}来自'React';
从“react router dom”导入{Route,Switch,withRouter};
从'react redux'导入{connect};
从“道具类型”导入道具类型;
从“../pages/Home.js”导入主页;
从“../pages/login.js”导入登录页面;
从“../pages/register.js”导入RegisterPage;
从“../pages/forgotPassword.js”导入ForgotPasswordPage;
从“../pages/mailConfirm.js”导入MailConfirmPage;
从“../pages/Page404.js”导入Page404;
从“/PrivateRoute.js”导入PrivateRoute
类RouteComponent扩展了组件{
render(){
返回(
);
}
}
函数MapStateTops(状态){
返回{
授权:state.login.successful
}
}
使用路由器导出默认值(connect(MapStateTops)(RouteComponent));
privaterout.js
import React, {Component} from 'react';
import { Redirect, Route } from 'react-router-dom';
const PrivateRoute = function PrivateRoute ({component: Component, authed, ...rest}) {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}
export default PrivateRoute
import React,{Component}来自'React';
从“react router dom”导入{Redirect,Route};
const PrivateRoute=函数PrivateRoute({component:component,authored,…rest}){
返回(
授权===true
?
: }
/>
)
}
导出默认PrivateRoute
在sagas中登录成功后,history.push将转到/mail确认组件。我看到的是浏览器中的地址栏更改为/mail确认,但页面仍然是登录页面
非常感谢您的帮助
谢谢
Sanjeev是因为您在引号中有
authed=“{this.props.authed}”
?Tryauthed={this.props.authed}
在没有引号的情况下尝试,仍然相同。不过,this.props.authed的价值是正确的。我在使用browserHistory实现这一点时一直遇到问题。如果您使用window.location.href=“/mail confirmation”
,可能会奏效。我找到了解决方案。问题出在浏览器路由器上。而不是使用从“react Router dom”导入{Router}的方法,这样做很有效。React router 4就是这种情况,是不是因为引号中有authed=“{This.props.authed}”
?Tryauthed={this.props.authed}
在没有引号的情况下尝试,仍然相同。不过,this.props.authed的价值是正确的。我在使用browserHistory实现这一点时一直遇到问题。如果您使用window.location.href=“/mail confirmation”
,可能会奏效。我找到了解决方案。问题出在浏览器路由器上。而不是使用从“react Router dom”导入{Router}的方法,这样做很有效。React路由器4就是这种情况
import React, {Component} from 'react';
import { Redirect, Route } from 'react-router-dom';
const PrivateRoute = function PrivateRoute ({component: Component, authed, ...rest}) {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}
export default PrivateRoute