【问题标题】:How to Guarantee Success of HTTP request with Fetch如何使用 Fetch 保证 HTTP 请求的成功
【发布时间】:2017-01-10 09:11:29
【问题描述】:

我试图了解处理fetch HTTP 请求并确保我收到请求的数据的正确方法。

我的意思是我的请求可能会出现问题,而所需的数据对我的应用程序至关重要。在那种情况下,更合适的处理方式是什么?只需创建一个新请求?

我如何将解决方案与reduxredux-thunk 结合起来?

谢谢

【问题讨论】:

    标签: http redux fetch redux-thunk


    【解决方案1】:

    编写使用 fetch 执行 HTTP 请求的 Redux Thunk Action Creator 指南

    序言

    本示例使用 isomorphic-fetch,它是一个基于 promise 的库,用于发出 HTTP 请求。但是,您可以使用不同的基于 Promise 的请求库(例如 Axios)运行此示例,它仍然可以工作。如果您不想使用这些库之一,可以将自己的 HTTP 请求包装在 Promise 中。

    快速 Redux Thunk 示例

    首先这里是一个从 redux-thunk 文档借来的自包含示例

    import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import rootReducer from './reducers/index';
    
    // set up store with redux thunk
    const store = createStore(
      rootReducer,
      applyMiddleware(thunk)
    );
    
    // thunk action creator
    function makeASandwichWithSecretSauce(forPerson) {
      return function (dispatch) {
        return fetchSecretSauce().then(
          sauce => dispatch(makeASandwich(forPerson, sauce)),
          error => dispatch(apologize('The Sandwich Shop', forPerson, error))
        );
      };
    }
    
    // we can now dispatch the result of our thunk action creator like any other action
    store.dispatch(makeASandwichWithSecretSauce('bob))
    

    用 Redux 操作表示 HTTP 请求的状态

    来自 Redux 文档:

    调用异步 API 时,有两个关键时刻 时间:您开始通话的那一刻,以及您接听的那一刻 一个答案(或超时)。我们首先需要定义动作及其 与对 任何给定主题 ID 的外部资源。

    代表 API 请求的 Promise 有三种可能的状态:

    • 待处理(已提出请求)
    • 已完成(请求成功)
    • 被拒绝(请求失败 - 或超时)

    代表请求承诺状态的核心动作创建者

    好的,让我们编写我们需要的核心动作创建者,以表示对给定主题 ID 的请求的状态。

    const fetchPending = (topicId) => {
      return { type: 'FETCH_PENDING', topicId }
    }
    
    const fetchFulfilled = (topicId, response) => { 
      return { type: 'FETCH_FULFILLED', topicId, response }
    }
    
    const fetchRejected = (topicId, err) => {
      return { type: 'FETCH_REJECTED', topicId, err }
    }
    

    请注意,您的 reducer 应该适当地处理这些操作。

    单个提取操作创建者的逻辑

    Fetch 是一个基于 Promise 的请求库。因此 axios.get 方法向给定的 url 发出请求并返回一个承诺,如果成功,该承诺将被解决,否则该承诺将被拒绝

    import fetch from 'isomorphic-fetch'
    
    const makeAPromiseAndHandleResponse = (topicId, url, dispatch) => {
        return fetch(url)
                 .then(response => {
                   dispatch(fetchFulfilled(topicId, response))
                 })
                 .catch(err => {
                   dispatch(fetchRejected(topicId, err))
                 }) 
    }
    

    如果我们的 HTTP 请求成功,我们的 Promise 将被解析并且 .then 中的代码将被执行。这将为我们的给定主题 id 调度一个 FETCH_FULFILLED 操作,并带有来自我们请求的响应(我们的主题数据)

    如果 HTTP 请求不成功,我们在 .catch 中的代码将被执行并调度一个 FETCH_REJECTED 操作,该操作将包含主题 ID 和请求期间发生的错误。

    我们将请求错误处理逻辑放在这里。这可能涉及调度一个或多个进一步的操作,这些操作可能会重新尝试 HTTP 请求或将另一个操作发送到备用 URL。

    由于这是一个异步过程,我们可以使用 thunk 动作创建器,该创建器将使用 Redux-thunk 中间件允许我们在未来调度其他异步动作。

    Think Action 创建者如何工作?

    我们的 thunk 动作创建者能够在未来的某个日期调度多个动作。

    它将调度的一组操作向我们的减速器提供有关我们的 HTTP 请求状态的信息。

    Thunk 这个词是延迟评估的同义词。

    这个单一的 thunk 动作创建者是一个动作创建者,将由我们的 redux thunk 中间件处理,因为它符合与 thunk 动作创建者关联的签名,即它返回一个函数。

    编写我们的 thunk 动作创建器

    export const fetchSomeStuff = (url) => {
        return dispatch => {
            fetchData().then(
                response => dispatch(setOurData(response.data)),
                error => dispatch(apologise(error))
            );
        };
    }
    

    我们的 thunk 动作创建者返回一个函数。这个函数可以像任何普通函数一样返回它想要的任何东西,所以如果我们想要,我们可以将它设置为返回一个 Promise。

    export const fetchSomeStuff = (url) => {
        return dispatch => {
            return fetchData().then(
                response => dispatch(setOurData(response.data)),
                error => dispatch(apologise(error))
            );
        };
    }
    

    上面的 fetchSomeStuff 函数是一个 thunk 动作创建器,它从 isomorphic-fetch 调用 fetch。因此,该动作创建者返回了一个承诺。

    因为当我们调用 fetchSomeStuff(我们的 thunk 动作创建者)时,我们在 thunk 动作创建者返回的函数中返回这个函数,所以我们将返回一个 Promise。这非常有用,尤其是对于我们可能希望在调用 thunk 动作创建者之后检查某些动作是否在某个时间点调度的测试。

    我们的 thunk 动作创建者返回我们在 fetchSomeStuff thunk 动作创建者中返回的函数。

    这是 Redux thunk 中执行此操作的代码:

    if (typeof action === 'function') {
      return action(dispatch, getState);
    }
    

    所以如果我们调用

    fetchSomeStuff('www.example.com')
    

    我们返回一个函数

    但是,如果我们调度 fetchSomeStuff

    store.dispatch(fetchAllItems('www.example.com'))
    

    我们得到了一个承诺。

    这两行代码的区别在于,当我们调度我们的 thunk 动作创建者而不是简单地调用它时,它会通过中间件链。 Redux thunk 知道如何处理函数并将调用它们。

    所以基本上这就是配置 redux-thunk 中间件并且我们调用 store.dispatch 时发生的情况

    我们的 thunk 被发送

    function thunkActionCreator(){
       return function middlewareInjectsStoreMethods({dispatch, getstate}){  
       }
    }
    

    当我们调度这个动作创建者时

    return action(dispatch, getState, extraArgument);
    

    我们之前在 redux thunk 中看到的这段代码将被执行

    if (typeof action === 'function') {
      return action(dispatch, getState)
    }
    

    然后我们返回在 thunk 动作创建器中调用嵌套函数的结果

    function thunkActionCreator(){
       return function middlewareInjectsStoreMethods({dispatch, getstate}){
       }
    }
    
    if (typeof action === 'function') {
        return action(dispatch, getState)
    }
    

    action 代表我们的 thunk 动作创建者,而在内部调用动作意味着我们返回名为 middlewareInjectsStoreMethods 的嵌套函数 打电话时

     return action(dispatch, getState) 
    

    返回我们的嵌套函数 (middlewareInjectsStoreMethods) 并给出 store 的 dispatch 和 getState 方法。

    在心理上我们可以认为 redux-thunk 这样做

    if (typeof thunkActionCreator  === 'function') {
         return function middlewareInjectsStoreMethods({dispatch,  getstate}){}
    }
    

    所以现在我们可以看到为什么我们必须在我们的 redux thunk 动作创建器中返回一个函数。 我们的动作创建者需要访问权限以在未来调度进一步的动作。通过返回一个函数,我们可以在以后调用它,并且仍然可以访问调度。这种优雅的做事方式是我喜欢 Redux 的部分原因。

    【讨论】:

      猜你喜欢
      • 2019-05-08
      • 2015-09-12
      • 2016-10-22
      • 2016-11-12
      • 2021-09-03
      • 1970-01-01
      • 2021-03-31
      • 2018-10-20
      相关资源
      最近更新 更多