API调用成功后显示加载状态和更改路径

时间:2018-02-10 04:09:01

标签: reactjs react-redux react-router-v4 react-router-dom

在开展辅助项目时,我遇到了react-router-dom的问题。

我想要实现的是:当我提交表单时,我需要将数据保存在我的服务器上。请求待处理时,我需要显示加载指示符。一旦服务器说一切正常,我需要在新页面上重定向用户

action.js

export const addNotification = value => async dispatch => {
   dispatch(addNotificationPending())

   try {
     const response = await client.createNotification(values)

     dispatch(addNotificationSuccess(response))
   } catch(e) {
     dispatch(addNotificationFailure())
   }
}

component.js

class CreateNotificationForm extends Component {
  onSubmit = (values) => {
    this.props.addNotification(parameters, history)
  }

  render() {
    const { isCreating } = this.props
    const submitBtnText = isCreating ? 'Creating...' : 'Submit'

    return (
      <Form>
        // content omitted
        <Submit value={submitBtnText} />
      </Form>
    )
  }
}

const mapStateToProps = (state) => ({
  isCreating: getIsFetching(state)
})
const mapDispatchToProps = (dispatch) => ({ // omitted })
connect(mapStateToProps, mapDispatchToProps)(CreateNotificationForm)

到目前为止一切顺利:当我提交表单时,表单的提交按钮会显示Creating...文字。

但是,如果请求成功,我如何告诉react-router加载新路径?

目前,我已使用withRouter并使用this.props.history作为this.props.addNotification的第二个参数来完成此操作。

效果很好,但似乎真的错了

我见过使用react-router-redux的解决方案,但我真的不想在我的商店中添加新的中间件。

我应该在我的组件中进行API调用并使用Promise吗?

任何帮助?

3 个答案:

答案 0 :(得分:1)

更新

在我自己的React项目上做了一些工作,并考虑到我处理路线变化的类似情况后,我决定改变原来的答案。我认为回调解决方案没问题,但是您已经提到的在组件内部进行API调用并使用promise的解决方案更好。我意识到我现在已经在我自己的应用程序中做了一段时间了。

我在我的应用程序中使用redux-form,它提供了可用于处理提交结果的onSubmitSuccess / onSubmitFail函数,并且每个函数都依赖于您返回一个promise(通常来自您的action creator)。

我认为React / Redux中最受欢迎的表单提交包之一支持这种模式,这表明它可能是一个很好用的模式。此外,由于react-router将历史记录传递到您的组件中,因此他们希望大多数人在组件内部进行大量程序化路由更改似乎是合乎逻辑的。

以下是您的代码的承诺解决方案的示例:

<强> action.js

export const addNotification = value => dispatch => {
  return new Promise(async (resolve, reject) => {
    dispatch(addNotificationPending())

    try {
     const response = await client.createNotification(values)

     dispatch(addNotificationSuccess(response))
     resolve(response)
    } catch(e) {
     dispatch(addNotificationFailure())
     reject(e)
    }
  })
}

<强> component.js

onSubmit = async () => {
  try {
    await this.props.addNotification(parameters)
    this.props.history.push('/new/route')
  } catch(e) {
    // could use a try/catch block here to display
    // an error to the user here if addNotification fails,
    // or go to a different route
  }
}

旧答案:

一个简单的解决方案是允许addNotification()接受回调函数作为可选的第二个参数。

export const addNotification = (value, callback=null) => async dispatch => {
   dispatch(addNotificationPending())

   try {
     const response = await client.createNotification(values)

     dispatch(addNotificationSuccess(response))
     (typeof callback === 'function') && callback()
   } catch(e) {
     dispatch(addNotificationFailure())
   }
}

然后在组件内部使用路由器转到新路由。

onSubmit = (values) => {
  this.props.addNotification(parameters, () => {
    this.props.history.push('/new/route')
  })
}

答案 1 :(得分:0)

您不应该在reducers或actions中编写异步调用,因为文档清楚地表明它们是纯函数。您将不得不引入一个redux-middleware,如redux-thunkredux-saga(我个人更喜欢sagas)

所有异步调用都将在中间件中发生,当成功时,您可以使用react-routers历史.replace().push()方法来更新路由。如果有意义,请告诉我

答案 2 :(得分:0)

您可以使用一种流行的套装

https://www.npmjs.com/package/axios

您可以像

一样实施登录
$sums=[];
foreach ($input AS $rec)
    @$sums[$rec['entry']['project_id']] += $rec['entry']['hours'];

您可以在调用api时编写加载程序登录

然后你可以在.then

中隐藏你的装载机