React Redux 的通用组件

Generic Components with React Redux

我对 redux 中的全局状态和可重用组件的概念有点纠结。

假设我有一个文件选择器组件,我想在我的应用程序状态中的多个位置使用它。创建 action/reducers 会导致大量膨胀,因为我必须处理带有动态后缀的状态和其他奇怪的事情,这些事情并没有真正让我觉得这是一种聪明的处理方式。

关于这些事情的普遍共识是什么?我只能看到两个解决方案:

有什么想法/最佳做法吗?谢谢

更新:澄清一下我描述的文件选择器不是一个简单的组件,它纯粹在客户端工作,但必须从服务器获取数据,还提供分页如过滤等。这就是为什么我还想重用大部分 client/server 交互。显示此组件的视图当然是愚蠢的,只显示来自状态的值 - 但我如何在应用程序周围的多个位置重用 actions/reducers?

通常,经验法则是您使用 redux store 来管理应用程序中的数据,也就是存储从服务器获取的项目和本地 react state 用于 ui 行为,例如在你的情况下文件上传。我会制作一个纯反应组件来管理文件上传,然后使用 redux-form 来管理特定的表单。

下面是我在项目中使用的组件示例

import React, {Component, PropTypes} from 'react';
import Button from 'components/Button';

class FileButton extends Component {
  static propTypes = {
    accept: PropTypes.string,
    children: PropTypes.any,
    onChange: PropTypes.func.isRequired
  };

  render() {
    const {accept, children, onChange} = this.props;
    return <Button {...this.props} onClick={() => this.file.click()}>
      <input
        ref={el => this.file = $(el)}
        type="file"
        accept={accept}
        style={{display: 'none'}}
        onChange={onChange}
      />
      {children}
    </Button>;
  }
}

export default FileButton;

我们得出结论,可重用组件必须有两种:

  • 哑组件,即仅接收道具并仅通过道具回调触发 "actions" 的组件。这些组件具有最小的内部状态或根本没有。这些是最常见的可重用组件,您的文件选择器可能会属于这种情况。样式化的文本输入或自定义列表也是很好的例子。

  • 提供自己的动作和减速器的连接组件。这些组件在应用程序中有自己的生命,并且独立于其他组件。一个典型的例子是 "top error message box",它在应用程序严重失败时显示在其他所有内容之上。在这种情况下,应用程序会触发一个 "error action" 并将适当的消息作为有效负载,并且在接下来的重新呈现中,消息框会显示在其余部分之上。

让你的减速器处理你的组件状态的多个实例。当您的 FileBrowser 组件出现在应用程序中时,只需为它的每个实例定义一些 "unique" ID,并将您的当前状态包装在一个对象中,并将此 uniqueIds 作为键,并将您的旧复杂状态作为值。

这是我多次使用的技巧。如果您的所有 FileBrowser 在编译时都是已知的,您甚至可以在 运行 您的应用程序之前设置初始状态。如果您需要支持 "dynamic" 个实例,只需创建一个 Action 来初始化给定 id 的状态。

您没有提供任何代码,但这里有一个可重复使用的 Todo reducer 的人为示例:

function todos(state={}, action){
  switch(action.type){
    case 'ADD_TODO':
      const id = action.todoListId
      return {
         ...state,
         [id]: {
            ...state[id],
            todos: [ ...state[id].todos, action.payload ]
         }
      }
      // ... 
  }
}