使用 Promise 中间件为 React-Redux 应用程序添加加载指示器

Posted

技术标签:

【中文标题】使用 Promise 中间件为 React-Redux 应用程序添加加载指示器【英文标题】:Add Loading Indicator for React-Redux app with Promise Middleware 【发布时间】:2017-09-25 11:20:00 【问题描述】:

我是反应 redux 的新手。我想在用户按下搜索按钮时添加加载文本,并在数据返回或操作完成时关闭文本。 在正常的异步函数中,我可以在回调之前和之后切换 isLoading 标志。

但是,在我的应用程序中,我正在调度一个返回“类型”和“有效负载”的操作,这是一个承诺。中间件 redux-promise 然后“自动”转换该承诺有效负载并将其发送到减速器。 换句话说,中间件在幕后为 Promise 执行 .then 操作,并为我的 reducer 提供正确的数据。

在这种情况下,我不确定如何将加载文本添加到我的视图中,因为一旦我调用 this.props.getIdByName(this.state.value),我不知道数据何时返回。 对我来说,合乎逻辑的地方是在 reducer 内,因为那是数据返回的时候。但是,我认为这将是一个不好的方法,因为减速器不应该执行这样的任务?

在我的组件中,我的提交具有以下功能

  handleSubmit(e) 
    e.preventDefault();
    this.props.getIdByName(this.state.value);
  

在我的 actions/index.js 文件中,我有以下动作生成器

export function getIdByName(name) 
    const FIELD = '/characters'
    let encodedName = encodeURIComponent(name.trim());
    let searchUrl = ROOT_URL + FIELD + '?ts=' + TS + '&apikey=' + PUBLIC_KEY + '&hash=' + HASH + '&name=' + encodedName;
    const request = axios.get(searchUrl)

    return 
        type: GET_ID_BY_NAME,
        payload: request
    

在我的 reducers/reducers.jsx 中

export default function (state = INITIAL_STATE, action) 
    switch (action.type) 
        case GET_ID_BY_NAME: 
            console.log(action.payload.data.data.results[0].id); <-- here the data comes back correctly because reduer called the promise and gave back the data for me
            return ...state, id: action.payload.data.data.results[0].id;
        default:
            return state;
    

在我的主 index.js 文件中,我使用以下中间件创建了商店

const createStoreWithMiddleware = applyMiddleware(
    promise,
    thunk
)(createStore);

【问题讨论】:

【参考方案1】:

当您在使用redux-promise 时以Promise 作为其有效负载分派操作时,redux-promise 中间件将捕获该操作,等到Promise 解析或拒绝,然后重新分派该操作,现在使用Promise 的结果作为其有效负载。这意味着您仍然可以处理您的操作,并且一旦您处理它,您就知道它已经完成了。所以你是对的,reducer 是处理这个问题的正确地方。

不过,你说得对,reducer 不应该有副作用。他们应该只建立新的状态。因此,答案是通过在 Redux 中更改应用程序的状态来显示和隐藏加载指示器:)

我们可以在我们的 Redux 存储中添加一个名为 isLoading 的标志:

const reducers = 
    isLoading(state = false, action) 
        switch (action.type) 
          case 'START_LOADING':
            return true;
          case 'GET_ID_BY_NAME':
            return false;
          default:
            return state;
        
    ,
    // ... add the reducers for the rest of your state here


export default combineReducers(reducers);

无论何时你要调用getIdByName,在调用它之前调度一个类型为'START_LOADING' 的动作。当getIdByNameredux-promise 重新调度时,您将知道加载已完成并且isLoading 标志将设置回false。

现在我们有了一个标志,指示我们是否正在将数据加载到 Redux 存储中。使用该标志,您可以有条件地呈现加载指示器。 :)

【讨论】:

【参考方案2】:

我相信 Pedro 的回答应该能让你开始,但我最近在我的应用程序中做了非常准确的 loader/pre-loader

最简单的方法是。

    在您的一个 reducer 中的 state 对象中创建一个新键,并将其命名为 showLoader: false。 在与之前相同的容器中(带有按钮的容器),创建一个mapStateToProps 并获取该状态属性showLoader。 在包含您尝试触发loader 的按钮的container 内,添加一个调用actiononClick 事件,例如displayLoader。在同一函数中还将this.props.showLoader 设置为true

    创建一个displayLoader 操作,编写如下内容:

    function displayLoader() 
        return 
            type: DISPLAY_LOADER,
            payload: 
        
    
    

    在减速器中,捕获此操作并在收到所需的payload 时将showLoader 设置回false

希望对你有帮助!

【讨论】:

以上是关于使用 Promise 中间件为 React-Redux 应用程序添加加载指示器的主要内容,如果未能解决你的问题,请参考以下文章

redux-promise:未捕获的 TypeError:中间件不是函数

REACT 如何使用 Redux 和 Axios(使用 promise 中间件)发出 AJAX 请求?

使用promise和socket.io中间件来实现redux

错误:操作必须是普通对象。相反,实际的类型是:'Promise'。您可能需要添加中间件

如何在 reducer 中处理 Redux 的 redux-promise 中间件 AJAX 错误?

同时启用 redux-promise 和 redux-saga 中间件似乎会导致问题