简体   繁体   中英

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

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.

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.

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.

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)
    }
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM