在 React 组件中订阅 redux 操作

Posted

技术标签:

【中文标题】在 React 组件中订阅 redux 操作【英文标题】:Subscribing to a redux action in a react component 【发布时间】:2018-11-03 10:14:31 【问题描述】:

我有一个从 Web 服务获取一些信息的异步​​ thunk,它可以调度三种类型的操作

FETCH_REQUESTED
FETCH_SUCCEEDED
FETCH_FAILED

最后,如果成功了;它返回实际响应或错误对象。

我有一个组件应该检测操作是否失败,最好订阅FETCH_FAILED 操作并根据错误类型(404/401 和其他状态代码)显示错误消息

export const fetchData = () => 
    return async (dispatch, getState) => 
        const appState = getState();

        const  uid  = appState.appReducer;

        await dispatch(fetchRequested());

        try 
            const response = await LookupApiFactory().fetch( uid );

            dispatch(fetchSucceeded(response));

            return response;
         catch (error) 
            dispatch(fetchFailed());

            return error;
        
    

我对 redux 和 react 还很陌生,所以我有点不确定我是否朝着正确的方向前进,我们将不胜感激。

【问题讨论】:

您没有订阅该操作。相反,您将组件映射到商店。当商店更新时,您的组件将相应地重新渲染。您可以使用 mapStateToProps 来做到这一点。 是的,我明白了,当我需要显示一个文本值或类似的东西时,这样做是完全可以的,但是当一个动作发生时,我需要根据它的结果运行一些代码,不知道该怎么做。 这段代码是在一个普通的类中,而不是一个反应组件吗? 是的,它在一个单独的类中。 我认为我遇到了与您遇到的问题类似的问题 - 我需要在成功的 API 调用上调用“成功”函数。但是,我需要监听该分派的操作,以便进行有意义的 UI 更改(在我的情况下,关闭模式)。它并不是真正属于 redux 状态的东西。在 Angular 的 ngxs 状态管理库中,您可以在分派特定操作时订阅商店。我基本上需要在这里做同样的事情,但是使用 redux。我目前正在使用回调,但它很脏。 【参考方案1】:

要实现适当的 redux 回调和存储机制,您应该有一个存储来保存所有数据,

const store = createStore(todos, ['Use Redux'])

然后,您将数据发送到存储,

store.dispatch(
  type: 'FETCH_FAILED',
  text: reposnse.status //Here you should give the failed response from api
);

然后,您可以使用订阅功能从任何组件的商店中获取值。任何时候调度一个动作时都会调用它,并且状态树的某些部分可能已经改变。

store.subscribe(()=>
  store.getState().some.deep.property
)

这是一个简单的 Redux 实现。随着您的应用程序变得越来越复杂,您需要将归约函数拆分为单独的函数,每个函数使用combineReducers 管理状态的独立部分。您可以从redux.js site获取更多信息

【讨论】:

【参考方案2】:

最常用的方法是使用来自react-redux 库的connect 函数。这是一个订阅状态变化的 HoC。看看这个库,它还允许你绑定你的动作创建者来调度,这让你能够从组件中调度你的动作。

你可以这样使用它:

import React from 'react';
import  connect  from 'react-redux';

const MyComponent = ( data, error ) => (
  <div>
    error && (
      <span>Error occured: error</span>
    )

    !error && (
      <pre>JSON.stringify(data, null, 2)</pre>
    )
  </div>
);

const mapStateToProps = (state) => (
  data: state.appReducer.data,
  error: state.appReducer.error
);

export default connect(mapStateToProps)(MyComponent);

您可以在 jsx 中使用条件渲染,如上所示,或使用保护子句,如下所示:

const MyComponent = ( data, error ) => 
  if (error) 
    return (
      <span>Error occured: error</span>
    );
  

  return (
    <pre>
      JSON.stringify(data, null, 2)
    </pre>
  );

【讨论】:

【参考方案3】:

假设减速器,

对于FETCH_FAILED 动作,你可以放一些有意义的标志来表示 有一些失败。基于该标志,您可以显示错误消息或执行其他操作。

const testReducers =(state,actione)=>

    case 'FETCH_FAILED' : 

        return 
            ...state, error_in_response : true 
        
    ;

    default : return state;

在您的容器中,您可以获取该标志并将其传递给您的组件。

假设combineReducers用来组合reducers;

const mapStateToProps=(state)=>

    return 
        error_in_response : state.testReducers.error_in_response
    

connect(mapStateToProps)(yourComponent)

在您的组件中,可以使用 this.props.error_in_response 访问它

【讨论】:

是的,但是检测标志已设置的正确位置是什么,例如显示警报? 这会将 reducer 映射到 props,但是我会在哪里根据更改显示警报? 在你的组件中传递使用 redux-connect 连接的标志 在渲染方法里面? 您可以在它内部或其他生命周期基础上使用组件安装/卸载顺序

以上是关于在 React 组件中订阅 redux 操作的主要内容,如果未能解决你的问题,请参考以下文章

使用 Redux 让 React 组件执行一次性操作?

React:如何从 Redux/Flux 操作访问组件引用?

来自根组件的 React/Redux 调度操作?

为 React 可重用组件设计 Redux 操作和化简器

使用 TypeScript 在 React 组件外部调度 Redux Thunk 操作

在 react js 功能组件中调度操作后如何立即在 redux store 中使用更新的值