如何让 redux 派发一个动作并返回一个承诺?

Posted

技术标签:

【中文标题】如何让 redux 派发一个动作并返回一个承诺?【英文标题】:How can I make redux dispatch an action as well as return a promise? 【发布时间】:2017-10-30 07:08:33 【问题描述】:

这是我在 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)
        )
    

我希望能够在调度后返回一个承诺,这样我就可以在组件中使用这样的函数 -

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

我知道我可以传入一个回调来使这项工作异步。但我想使用 ES6 的 Promise 特性。我有点困惑如何做到这一点。

【问题讨论】:

function (dispatch) .then((response) => 都没有返回任何东西,所以这是一个开始的问题 刚从axios返回:return axios.post('http://localhost:8080/api/song/create' ... 【参考方案1】:

我认为使用分派操作的返回值不是很“反应”的方式。

使用Redux Saga,例如here,有一种更好的方法可以解决此类“复杂”情况。

虽然,我过去以这种方式通过调度操作使用返回值:

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

【讨论】:

【参考方案2】:

首先,你需要返回axios调用。

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

您的 createSong 函数正在返回另一个函数(所以它是一个 curried 函数)。

因此,

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

在我看来非常有效。

【讨论】:

【参考方案3】:

如果你想使用完整的 ES6,你应该使用 async/await 语法。这完全消除了处理承诺的需要。

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)
    
  

createSong 返回的匿名函数用新的async 关键字标记。这意味着匿名函数现在将返回一个隐式 Promise。

async 关键字还允许您在函数体中使用await,这样您就可以将await 异步调用axios.post 视为同步调用。

另一个优点是您可以重新使用普通的try / catch 块。这些实际上是在解决和拒绝幕后的隐含承诺,但它们以正常方式行事。

因为匿名函数实际上是返回一个 Promise,所以在调用链的上层,无论你在哪里调用 createSong(...) 函数,你也可以使用 async / await 语法 ... 等等。没有更多的回调,也没有更显式的 Promise 处理。

【讨论】:

这可以在不使用async/await的情况下完成。

以上是关于如何让 redux 派发一个动作并返回一个承诺?的主要内容,如果未能解决你的问题,请参考以下文章

如何键入 Redux thunk 动作创建者以返回承诺

另一个组件如何在 react/redux 中监听另一个组件的动作?

如何让 React Redux 异步操作返回一个承诺?

Redux Thunk, Sequelize (Bluebird) - 向动作创建者“链”返回承诺

React Redux 添加额外的操作字段导致承诺返回不同

Redux thunk:从分派的动作返回承诺