[英]redux saga and history.push
Backgrond:背景:
I am creating a Login
component.我正在创建一个Login
组件。
saga.js
is composed by 3 functions saga.js
由 3 个函数组成
1. rootSaga
. 1. rootSaga
。 It will execute the list of sagas
inside它将执行里面的sagas
列表
2. watchSubmitBtn
. 2. watchSubmitBtn
。 It will watch the click on the submit button and dispatch an action.它将观察提交按钮上的点击并发送一个动作。
3. shootApiTokenAuth
will receive dispatched action
and process axios.post
the return value is promise
object shootApiTokenAuth
会接收dispatched action
并处理axios.post
,返回值为promise
对象
In action:在行动:
Backend returns 400
to the React
.后端返回400
给React
。 This case no problem I can read the payload
and display in the render()
easily.这种情况下没问题,我可以轻松读取payload
并在render()
显示。 But when 200
is returned.但是当返回200
时。 I need to let user go to the url /companies
.我需要让用户转到 url /companies
。
Attempt:试图:
I had tried put this.props.history.push('/companies');
我试过把this.props.history.push('/companies');
in the componentWillUpdate()
, but it does not work.在componentWillUpdate()
,但它不起作用。 I have to click Submit
2 times to get React understand that token
has been saved.我必须单击Submit
2 次才能让 React 了解token
已保存。
Login.js
import React, {Component} from 'react';
import ErrorMessage from "../ErrorMessage";
import {Field, reduxForm} from 'redux-form';
import {connect} from 'react-redux';
import {validate} from '../validate';
import {SUBMIT_USERNAME_PASSWORD} from "../../constants";
class Login extends Component {
constructor(props) {
//Login is stateful component, but finally action will change
//reducer state
super(props);
const token = localStorage.getItem('token');
const isAuthenticated = !((token === undefined) | (token === null));
this.state = {
token,
isAuthenticated,
message: null,
statusCode: null
};
}
onSubmit(values) {
const {userid, password} = values;
const data = {
username: userid,
password
};
this.props.onSubmitClick(data);
}
componentWillUpdate(){
console.log('componentWillUpdate');
if(this.props.isAuthenticated){
this.props.history.push('/companies');
}
}
renderField(field) {
const {meta: {touched, error}} = field;
const className = `'form-group' ${touched && error ? 'has-danger' : ''}`;
console.log('renderField');
return (
<div className={className}>
<label>{field.label}</label>
<input
className="form-control"
type={field.type}
placeholder={field.placeholder}
{...field.input}
/>
<div className="text-help">
{touched ? error : ''}
</div>
</div>
);
}
render() {
const {handleSubmit} = this.props;
return (
<div>
<ErrorMessage
isAuthenticated={this.props.isAuthenticated}
message={this.props.message}
/>
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field
name="userid"
component={this.renderField}
placeholder="User ID"
type="text"
/>
<Field
name="password"
component={this.renderField}
placeholder="Password"
type="password"
/>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
<a className='btn btn-primary' href="https://www.magicboxasia.com/">Sign up</a>
</div>
);
}
}
const onSubmitClick = ({username, password}) => {
return {
type: SUBMIT_USERNAME_PASSWORD,
payload: {username, password}
};
};
const mapStateToProps = (state, ownProps) => {
return {
...state.login
}
};
export default reduxForm({
validate,
form: 'LoginForm'
})(
connect(mapStateToProps, {onSubmitClick})(Login)
);
saga.ja
const shootApiTokenAuth = (values) =>{
const {username, password} = values;
return axios.post(`${ROOT_URL}/api-token-auth/`,
{username, password});
};
function* shootAPI(action){
try{
const res = yield call(shootApiTokenAuth, action.payload);
yield put({
type: REQUEST_SUCCESS,
payload: res
});
}catch(err){
yield put({
type: REQUEST_FAILED,
payload: err
});
}
}
function * watchSubmitBtn(){
yield takeEvery(SUBMIT_USERNAME_PASSWORD, shootAPI);
}
// single entry point to start all Sagas at once
export default function* rootSaga() {
yield all([
watchSubmitBtn()
])
}
Problem:问题:
How can I set the component state and push
to url /companies
?如何设置组件状态并push
送到 url /companies
? after backend returns 200
?后端返回200
?
I usually handle conditional navigation like that in the saga.我通常在传奇中处理条件导航。
The simplest answer with the existing code is to pass a history object as a prop in the SUBMIT_USERNAME_PASSWORD action and do the history.push() call in the success case of the saga, something like:现有代码最简单的答案是在 SUBMIT_USERNAME_PASSWORD 操作中将历史对象作为道具传递,并在传奇成功的情况下执行 history.push() 调用,例如:
const onSubmitClick = ({username, password}) => {
const { history } = this.props;
return {
type: SUBMIT_USERNAME_PASSWORD,
payload: {username, password, history}
};
};
....... ......
function* shootAPI(action){
try{
const res = yield call(shootApiTokenAuth, action.payload);
const { history } = action.payload;
yield put({
type: REQUEST_SUCCESS,
payload: res
});
history.push('/companies');
}catch(err){
yield put({
type: REQUEST_FAILED,
payload: err
});
}
}
import { push } from 'react-router-redux';
yield put(push('/path-to-go'));
solved my problem解决了我的问题
I am not as experienced in react but you could achieve it as follows:我在反应方面没有经验,但您可以按以下方式实现:
1.Create a new Module: history-wrapper.ts 1.新建一个模块: history-wrapper.ts
export class HistoryWrapper {
static history;
static init(history){
HistoryWrapper.history = history;
}
}
2.In you login.jsx 2.在你登录.jsx
HistoryWrapper.init(history);//initialize history in HistoryWrapper
3.Subsequently anywhere in your app 3.随后在您的应用程序中的任何位置
HistoryWrapper.history.push('/whatever');
React has additional lifecycle. React 有额外的生命周期。 I just know it today.我今天才知道。 They are many of them.他们中有很多人。
componentDidUpdate() {
this.props.history.push('/companies');
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.