问题
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