我正在尝试进行一项操作,该操作将进行两次单独的 API 调用,然后将数据合并在一起,然后传递给我的减速器。我尝试使用 promise 进行第一次调用,然后使用 axios 的 transformResponse 将数据合并到其中,但我不断收到Uncaught Error: Actions must be plain objects。使用自定义中间件进行异步操作。错误。
最好的方法是什么?
我正在尝试进行一项操作,该操作将进行两次单独的 API 调用,然后将数据合并在一起,然后传递给我的减速器。我尝试使用 promise 进行第一次调用,然后使用 axios 的 transformResponse 将数据合并到其中,但我不断收到Uncaught Error: Actions must be plain objects。使用自定义中间件进行异步操作。错误。
最好的方法是什么?
重要的是,reducer 总是同步的。因此,reducer 不应该收到承诺。操作应仅包含纯数据并采用以下形式:
{
type: 'ADD_TODO',
payload: {
text: 'Do something.'
}
}
redux-promise 允许我们在动作的有效负载中放置一个承诺。
一旦 redux-promise 添加到中间件链中,我们就可以调度在其有效负载属性中具有承诺的操作。
redux-promise 中间件将在到达 store 之前处理此操作,并在 promise 被解决或拒绝后调度任何进一步的操作,并且有效负载将包含每种情况下的响应或错误。
一旦 promise 被解决或拒绝,redux-promise 调度的这些进一步的动作是同步的,就像调度的任何动作一样。请记住,我们中间件的工作是在操作负载中的承诺解决或拒绝后调度额外的操作。
调度动作 --> 中间件(redux-promise 调度进一步的动作) --> 减速器从这些进一步的动作中获取错误或数据 --> 存储由减速器更新
这是一个独立的示例,我们将向开放的电影数据库 api 请求电影数据,以演示 redux-promise 的工作原理。
先到店
store.js
import { createStore, combineReducers, applyMiddleware } from 'redux'
import promiseMiddleware from 'redux-promise'
let rootReducer = combineReducers(reducers)
let store = createStore(
rootReducer,
applyMiddleware(promiseMiddleware)
)
现在我们需要传递 Redux 的 applyMiddleware 函数作为参数来创建 store,然后将 redux-promise 作为参数提供给 applyMiddleware。
现在是动作创建者。
当在下面调用 action creator 函数时,将发出 axios 请求。这个请求会返回一个 promise,然后通过我们的 redux-promise 中间件传递。
动作/index.js
export function requestMovie(movieTitle) {
// create the url for our api request
const url = `http://www.omdbapi.com/??=${movieTitle}&y=&plot=short&r=json`
return { // return our action
type: 'REQUEST_MOVIE',
payload: axios.get(url) // this .get method returns a promise
}
}
然后我们的 reducer 将得到我们承诺的结果。
main 函数处理在 promise 被拒绝或解决后由 redux-promise 中间件调度的操作
减速器/index.js
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
movies: movies,
err: err
});
function err(err = false, action){
switch (action.type) {
case 'REQUEST_MOVIE':
return(action.payload.response.status !== 200)
}
return err;
}
function movies(movies = [], action){
switch (action.type) {
case 'REQUEST_MOVIE':
// if promise was not rejected the data property on our action payload will exist comprising the movie data that we requested
if(action.payload.response.status === 200){
return [...movies, action.payload.response.data]
} else{
return [movies]
}
}
return movies
}
export default rootReducer;