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

Posted

技术标签:

【中文标题】为 React 可重用组件设计 Redux 操作和化简器【英文标题】:Design Redux actions and reducers for a React reusable component 【发布时间】:2015-11-23 05:22:27 【问题描述】:

我正在使用 Redux 和 React 开发一个大型应用程序,我决定制作一些可重用的组件,例如自定义复选框和单选按钮。

由于我想将此信息存储到 Redux 存储中以便能够轻松地调试应用程序的状态,并且相同的组件在任何地方都具有相同的功能,因此为每个组件创建 reducer 和操作似乎是个好主意。

然而 Redux reducer 返回一个新状态并将其保存在 store 中,并使用 reducer 的名称作为键,这禁止在同一页面中使用相同的 action 和 reducer 但保持不同的相同类型的多个组件州。

我认为这个问题有两种解决方案:

为我使用的每个组件创建不同的操作和减速器,即使组件和它的功能是相同的。这种解决方案似乎不是一个好的解决方案,因为会有很多冗余代码。

创建具有足够参数的操作,以便能够区分 reducer 中的每个操作,这样只会更改指定的状态部分。

我选择了第二个选项。

CheckBox 组件的操作文件:

import createAction from 'redux-actions';

/****** Actions ******/
export const CHANGE_CHECKBOX_STATE = "CHANGE_CHECKBOX_STATE";

/****** Action creators ******/
export const changeCheckboxState = createAction(CHANGE_CHECKBOX_STATE, (block, name, state) => 
  return 
    block,
    name,
    state: 
      checked: state,
    
  ;
);

CheckBox 组件的 reducers 文件:

import handleActions from 'redux-actions';

import CHANGE_CHECKBOX_STATE from './CheckBox.actions';

export const checkBoxComponent = handleActions(
  CHANGE_CHECKBOX_STATE: (state, action) => (
    [action.payload.block]: 
      [action.payload.name]: action.payload.state
    
  )
, );

我使用block 指定页面,name 指定特定组件的名称(例如性别)和状态,以及具有新状态的对象。

但是这个解决方案也有一些问题:

无法指定每个组件的初始状态,因为状态的键是动态的。 具有大量嵌套状态的存储结构非常复杂。 按组件而不是按表单聚合数据,这会使调试复杂化,并且在逻辑上不正确。

我没有足够的使用 Redux 和 React 的经验来想出一个更好的解决方案来解决这个问题。但在我看来,我遗漏了一些关于 React-Redux 关系的重要内容,这引发了一些问题:

将这个可重用组件的状态存储到 Redux 存储中是个好主意吗?

将 React 组件与 Redux 操作和 reducer 绑定在一起是不是错了?

【问题讨论】:

我不明白您为什么需要像这样存储控件的状态?没有实际数据支持吗?而且这些数据并没有给出关于它是如何渲染的废话?对我来说似乎很臃肿。 @ChrisMartin 我试图在这里解释我是如何做出这个决定的,但我也说我知道我做错了什么,我只是不明白它是什么。你能解释一下你会如何设计它吗?也许这样我会看到我的方法有什么问题。感谢您的回复! 请观看这些视频:https://egghead.io/series/getting-started-with-redux... 【参考方案1】:

不要根据使用该状态的组件来描述您的 Redux reducer(您的整体应用程序状态)。以另一种方式跟踪它,以描述性方式描述您的应用程序状态,然后让您的“愚蠢”组件使用该描述性状态。

与其跟踪“与 foo 相关的表单的此复选框的状态”,不如跟踪“foo 的此布尔值”,然后让复选框使用该状态。

复选框的示例商店:

const initialState = 
    someFooItem:  isCertainType: false 
;

export function foos(state = initialState, action) 
    switch(action.type)
        case(UPDATE_FOO_VALUE):
            return 
                ...state, 
                [action.payload.id]: 
                    isCertainType: action.payload.isCertainType
                
            
    

消费商店的示例复选框

class CheckBox extends React.Component 
    render() 
        return <input type="checkbox" checked=this.props.checked />
    

父组件

class ParentComponent extends React.Component 
     render() 
         return <CheckBox checked=this.foo.isCertainType />
     

【讨论】:

如果我理解正确,您的解决方案并不能完全解决我的问题,因为您概括了复选框的形式,但是如果我有三个复选框,每个复选框都有不同的兴趣(例如,运动, Adventure, Cooking) 对于每一个,我都需要创建一个不同的 reducer,即使功能相同。 运动、冒险、烹饪都是“兴趣”,所以你可以有一个像 interests: cooking: true, sports: false, adventure: false 这样的 reducer 并用它来表示视图。【参考方案2】:

这里的根本错误是你有 0 个哑组件。像复选框这样的基本控件应该是只使用道具的哑组件,它们的父级有责任为特定的复选框选择和更新适当的状态。

【讨论】:

Nono,都是哑组件,actions和reducers只供父组件和store使用。

以上是关于为 React 可重用组件设计 Redux 操作和化简器的主要内容,如果未能解决你的问题,请参考以下文章

本地化 React 和 React-Native 组件,使其尽可能可重用

React, Redux Application - 传递初始状态的最佳模式

使用 Redux Hooks 而不是 connect() 好的设计吗?

React-Redux 设计方法 - 可编辑文本字段双向绑定的 Redux 操作或本地函数

React:如何将可重用组件与通常的哑组件连接起来

React 中的可重用组件