web-dev-qa-db-ja.com

redux sagaとhistory.push

Backgrond:
Loginコンポーネントを作成しています。

_saga.js_は3つの関数で構成されています
1。 rootSaga。内部でsagasのリストを実行します
2。 watchSubmitBtn。送信ボタンのクリックを監視し、アクションをディスパッチします。
3。 shootApiTokenAuthはディスパッチされたactionを受け取り、_axios.post_を処理します。戻り値はpromiseオブジェクトです

動作中:
バックエンドは_400_をReactに返します。この場合、payloadを読み取ってrender()に簡単に表示できます。ただし、_200_が返された場合。ユーザーに_/companies_というURLにアクセスさせる必要があります。

試行:
this.props.history.Push('/companies');componentWillUpdate()を入れてみましたが、機能しません。 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()
  ])
}
_

問題:
コンポーネントの状態とPushをURL _/companies_に設定するにはどうすればよいですか?バックエンドが_200_を返した後?

6
Sarit

私は通常、佐賀でそのような条件付きナビゲーションを処理します。

既存のコードで最も簡単な答えは、履歴オブジェクトを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
    });
  }
}
6
brub
import { Push } from 'react-router-redux';    

yield put(Push('/path-to-go'));

私の問題を解決しました

2

私は反応の経験はあまりありませんが、次のようにして達成できます。

1.新しいモジュールを作成します:history-wrapper.ts

export class HistoryWrapper {
  static history;
  static init(history){
    HistoryWrapper.history = history;
  }
}

2.あなたの中login.jsx

  HistoryWrapper.init(history);//initialize history in HistoryWrapper

3.アプリ内のその後の任意の場所

  HistoryWrapper.history.Push('/whatever');
1
dasfdsa

Reactには追加のライフサイクルがあります。今日はそれを知っています。それらの多くです。

componentDidUpdate() {
    this.props.history.Push('/companies');
  }
0
Sarit