React-Router:如何在路由转换之前等待异步操作 [英] React-Router: how to wait for an async action before route transition

查看:301
本文介绍了React-Router:如何在路由转换之前等待异步操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以在特定路由上调用称为thunk的异步redux动作,并且在响应成功或失败之前不执行转换?

Is it possible to call an async redux action known as a thunk on a particular route and not perform the transition until the response has succeeded or failed?

用例

我们需要从服务器加载数据并用初始值填写表格.从服务器获取数据之前,这些初始值不存在.

We need to load data from the server and fill a form with initial values. These initial values don't exist until the data is fetched from the server.

像这样的一些语法会很棒:

some syntax like this would be great:

<Route path="/myForm" component={App} async={dispatch(loadInitialFormValues(formId))}>

推荐答案

要回答最初的问题,即在响应成功或失败之前,禁止过渡到新路线:

由于您正在使用redux thunk,因此操作创建者成功或失败会触发重定向.我不知道您的特定动作/动作创建者是什么样的,但是这样的方法可能有效:

Because you're using redux thunk you could have the success or failure in the action creator trigger the redirect. I don't know what your specific action / action creator looks like but something like this could work:

import { browserHistory } from 'react-router'

export function loadInitialFormValues(formId) {
  return function(dispatch) {
    // hit the API with some function and return a promise:
    loadInitialValuesReturnPromise(formId)
      .then(response => {
        // If request is good update state with fetched data
        dispatch({ type: UPDATE_FORM_STATE, payload: response });

        // - redirect to the your form
        browserHistory.push('/myForm');
      })
      .catch(() => {
        // If request is bad...
        // do whatever you want here, or redirect
        browserHistory.push('/myForm')
      });
  }
}

跟进.在组件上的路径/componentWillMount上显示路线并显示微调器时加载数据的常见模式:

从关于异步操作的redux文档 http://redux.js.org/docs/advanced/AsyncActions.html

From the redux docs on async actions http://redux.js.org/docs/advanced/AsyncActions.html

  • 通知减速器该请求已开始的动作.
  • An action informing the reducers that the request began.

Reducer可以通过在以下位置切换isFetching标志来处理此操作 状态.这样,用户界面就知道该显示微调框了.

The reducers may handle this action by toggling an isFetching flag in the state. This way the UI knows it’s time to show a spinner.

  • 通知缩减程序请求已成功完成的动作.

reduce可以通过将新数据合并到 声明他们管理并重置isFetching.用户界面会隐藏 微调器,并显示获取的数据.

The reducers may handle this action by merging the new data into the state they manage and resetting isFetching. The UI would hide the spinner, and display the fetched data.

  • 通知减速器该请求失败的动作.

Reducer可以通过重置isFetching来处理此操作. 此外,某些减速器可能希望存储错误消息,因此 用户界面可以显示它.

The reducers may handle this action by resetting isFetching. Additionally, some reducers may want to store the error message so the UI can display it.

我按照您的情况作为大致指导,遵循了以下一般模式.您不必使用诺言

I followed this general pattern below using your situation as a rough guideline. You do not have to use promises

// action creator:
export function fetchFormData(formId) {
  return dispatch => {
    // an action to signal the beginning of your request
    // this is what eventually triggers the displaying of the spinner
    dispatch({ type: FETCH_FORM_DATA_REQUEST })

    // (axios is just a promise based HTTP library)
    axios.get(`/formdata/${formId}`)
      .then(formData => {
        // on successful fetch, update your state with the new form data
        // you can also turn these into their own action creators and dispatch the invoked function instead
        dispatch({ type: actions.FETCH_FORM_DATA_SUCCESS, payload: formData })
      })
      .catch(error => {
        // on error, do whatever is best for your use case
        dispatch({ type: actions.FETCH_FORM_DATA_ERROR, payload: error })
      })
  }
}

// reducer

const INITIAL_STATE = {
  formData: {},
  error: {},
  fetching: false
}

export default function(state = INITIAL_STATE, action) {
  switch(action.type) {
    case FETCH_FORM_DATA_REQUEST:
      // when dispatch the 'request' action, toggle fetching to true
      return Object.assign({}, state, { fetching: true })
    case FETCH_FORM_DATA_SUCCESS:
      return Object.assign({}, state, {
        fetching: false,
        formData: action.payload
      })
    case FETCH_FORM_DATA_ERROR:
      return Object.assign({}, state, {
        fetching: false,
        error: action.payload
      })
  }
}

// route can look something like this to access the formId in the URL if you want
// I use this URL param in the component below but you can access this ID anyway you want:
<Route path="/myForm/:formId" component={SomeForm} />

// form component
class SomeForm extends Component {
  componentWillMount() {
    // get formId from route params
    const formId = this.props.params.formId
    this.props.fetchFormData(formId)
  }

  // in render just check if the fetching process is happening to know when to display the spinner
  // this could also be abstracted out into another method and run like so: {this.showFormOrSpinner.call(this)}
  render() {
    return (
      <div className="some-form">
        {this.props.fetching ? 
          <img src="./assets/spinner.gif" alt="loading spinner" /> :
          <FormComponent formData={this.props.formData} />
        }
      </div>
    )
  }
}

function mapStateToProps(state) {
  return {
    fetching: state.form.fetching,
    formData: state.form.formData,
    error: state.form.error
  }
}

export default connect(mapStateToProps, { fetchFormData })(SomeForm)

这篇关于React-Router:如何在路由转换之前等待异步操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆