简体   繁体   English

redux 传奇和 history.push

[英]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 .后端返回400React 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM