How can I make redux dispatch an action as well as return a promise?

时光毁灭记忆、已成空白 提交于 2021-01-27 14:10:40

问题


Here is my function in songAction.js

export function createSong(title, url, token) {

    axios.defaults.headers.common['Authorization'] = token

    return function (dispatch) {
        axios.post('http://localhost:8080/api/song/create', {
            title,
            link: url

        })
        .then((response) => {
            console.log('the response was', response)
            if(response.data.success){
                dispatch({type: "CREATE_SONG_FULFILLED", payload: response.data.song})
            } else {
                dispatch({type: "CREATE_SONG_REJECTED", payload: response.data})

            }
        })
        .catch((err) => {
            dispatch({type: "CREATE_SONG_REJECTED", payload: err})
        })
    }
}

I want to be able to return a promise after dispatching so I can use the function like this inside a component -

 createSong(title, url, token)
   .then((result) =>{
        // do stuff with result 
     })

I know I can pass in a callback to make this work async.. but I want to use ES6 features of promises. And I'm a little confused how I can do this.


回答1:


If you want to go full ES6 you should use the async/await syntax. This eliminates the need to deal with promises at all.

export function createSong (title, url, token) {
  axios.defaults.headers.common['Authorization'] = token
  return async (dispatch) => {
    try {
      const response = await axios.post('http://localhost:8080/api/song/create', {
        title,
        link: url
      })
      console.log('the response was', response)
      if (response.data.success) {
        dispatch({type: 'CREATE_SONG_FULFILLED', payload: response.data.song})
      } else {
        dispatch({type: 'CREATE_SONG_REJECTED', payload: response.data})
      }
    } catch (err) {
      dispatch({type: 'CREATE_SONG_REJECTED', payload: err})
    }
  }
}

The anonymous function returned by createSong is marked with the new async keyword. This means that the anonymous function will now return an implicit Promise.

The async keyword also allows you to use await in the body of the function so you can await the async call to axios.post and so treat it as if it were a synchronous call.

Another advantage is that you can go back to using normal try / catch blocks. These are actually resolving and rejecting the implicit promise behind the scenes but they act in the normal way.

Because the anonymous function is actually returning a Promise, higher up the call chain, wherever you call the createSong(...) function, you can also use the async / await syntax ... and so on. No more callbacks, and no more explicit Promise handling.




回答2:


First of all, you need to return the axios call.

...
return function (dispatch) {
  return axios.post('http://localhost:8080/api/song/create', {
    title,
    link: url
  })
...

Your createSong function is returning another function (so it's a curried function).

Therefore,

createSong(title, url, token)(dispatch)
.then(()=>{
  // something
})

looks to me pretty valid.




回答3:


I think that it isn't very 'React' way to use return values of dispatched actions.

There is a better way how to solve 'complex' situations like this using Redux Saga, example here.

Although, I used returned values by dispatched actions in this way in the past:

export const updatePage = (id, batch) => {
  return dispatch => {
    dispatch({
      type: 'UPDATE_PAGE',
      payload: {
        id
      }
    })

    // Make an API call
    return requestUpdatePages(
      id, batch
    ).then(data => {
      // When API call is successful
      return dispatch({
        type: 'UPDATE_PAGE_SUCCESS',
        payload: {
          id,
          data
      })
    })
    .catch(error => {
      // When API call fails
      return dispatch({
        type: 'UPDATE_PAGE_FAIL',
        payload: {
          error,
          id
        },
        error: true
      })
    })
  }
}

// After dispatch is bound to action creators
// you can use it like this

handleClick(id) {
  const { updatePage } = this.props
  updatePage(id).then(action => {
    if(action.type === 'UPDATE_PAGE_SUCCESS') {
      console.log('Whee, page has been updated!', action.payload.data)
    } else {
      console.error('Something went wrong :-( ', action.payload.error)
    }
  })
}


来源:https://stackoverflow.com/questions/44251550/how-can-i-make-redux-dispatch-an-action-as-well-as-return-a-promise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!