API 调用成功显示加载状态和更改路由
Display loading state and change route when API call is successfull
在做一个副项目时,我遇到了 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
吗?
有什么帮助吗?
您不应在 reducer 或操作中编写异步调用,因为文档明确建议它们是纯函数。你将不得不引入像 redux-thunk
或 redux-saga
这样的 redux 中间件(我个人更喜欢 sagas)
您所有的异步调用都将在中间件内部发生,当它成功时,您可以使用 react-routers history .replace()
或 .push()
方法来更新您的路由。让我知道是否有意义
你可以使用一个流行的包 axios
看这里https://www.npmjs.com/package/axios
您可以像
一样实现您的登录
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
您可以在调用 api
时编写加载程序登录
然后你可以在 .then
中隐藏你的加载程序
更新:
在我自己的 React 项目上做了一些工作,并考虑了我在那里处理路由更改的类似情况,我决定改变我原来的答案。我认为回调解决方案还可以,但是您已经提到的在组件内部进行 API 调用并使用承诺的解决方案更好。我意识到我实际上已经在我自己的应用程序中这样做了一段时间。
我在我的应用程序中使用 redux-form,它提供了 onSubmitSuccess/onSubmitFail 函数,您可以使用它们来处理提交结果,并且每个函数都依赖于您返回一个承诺(通常来自您的操作创建者) .
我认为 React/Redux 中最流行的表单提交包之一支持此模式这一事实表明它可能是一个很好用的模式。此外,由于 react-router 将历史记录传递到您的组件中,因此他们希望大多数人在组件内部进行大量程序化路由更改似乎是合乎逻辑的。
下面是使用您的代码的 promise 解决方案示例:
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')
})
}
在做一个副项目时,我遇到了 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
吗?
有什么帮助吗?
您不应在 reducer 或操作中编写异步调用,因为文档明确建议它们是纯函数。你将不得不引入像 redux-thunk
或 redux-saga
这样的 redux 中间件(我个人更喜欢 sagas)
您所有的异步调用都将在中间件内部发生,当它成功时,您可以使用 react-routers history .replace()
或 .push()
方法来更新您的路由。让我知道是否有意义
你可以使用一个流行的包 axios
看这里https://www.npmjs.com/package/axios
您可以像
一样实现您的登录axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
您可以在调用 api
时编写加载程序登录然后你可以在 .then
中隐藏你的加载程序更新:
在我自己的 React 项目上做了一些工作,并考虑了我在那里处理路由更改的类似情况,我决定改变我原来的答案。我认为回调解决方案还可以,但是您已经提到的在组件内部进行 API 调用并使用承诺的解决方案更好。我意识到我实际上已经在我自己的应用程序中这样做了一段时间。
我在我的应用程序中使用 redux-form,它提供了 onSubmitSuccess/onSubmitFail 函数,您可以使用它们来处理提交结果,并且每个函数都依赖于您返回一个承诺(通常来自您的操作创建者) .
我认为 React/Redux 中最流行的表单提交包之一支持此模式这一事实表明它可能是一个很好用的模式。此外,由于 react-router 将历史记录传递到您的组件中,因此他们希望大多数人在组件内部进行大量程序化路由更改似乎是合乎逻辑的。
下面是使用您的代码的 promise 解决方案示例:
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')
})
}