简体   繁体   English

使用React Redux的通用组件

[英]Generic Components with React Redux

I am struggling a bit with the concept of global state and reusable components in redux. 我正在努力与redux中的全局状态和可重用组件的概念。

Let's say I have a component that's a file-selector that I want to use in multiple places inside my applications state. 假设我有一个组件,它是一个文件选择器,我想在我的应用程序状态中的多个位置使用。 Creating action/reducers leads to a lot of bloat as I have to handle states with dynamic suffixes and other weird things that just don't really strike me as a smart way to go about things. 创建动作/减速器会导致很多膨胀,因为我必须处理具有动态后缀和其他奇怪事物的状态,这些事情并没有真正让我觉得这是一种聪明的方式。

What's the general consensus on these things? 这些事情的一般共识是什么? I can only see two solutions: 我只能看到两种解决方案:

  • Make the file-selector component have local state ( this.setState/this.getState ) 使文件选择器组件具有本地状态( this.setState/this.getState

  • Make the file-selector be part of the global state but in it's own unique reducer that I can read from once the operation of the component is done? 使文件选择器成为全局状态的一部分,但是在它自己独特的reducer中,一旦组件的操作完成,我可以读取它吗?

Any ideas / best practices? 任何想法/最佳实践? Thanks. 谢谢。

Update : To clarify the file selector I am describing is not a simple component that works purely on the client side but has to fetch data from the server, provide pagination as well as filtering etc.. That's why I'd also like to reuse most of the client/server interaction. 更新 :澄清我描述的文件选择器不是一个纯粹在客户端工作的简单组件,但必须从服务器获取数据,提供分页以及过滤等。这就是为什么我也想重用大多数客户端/服务器交互。 The views that display this component are of course dumb and only display values from the state - but how do I reuse the actions/reducers in multiple places around the application? 显示此组件的视图当然是愚蠢的,只显示来自状态的值 - 但是如何在应用程序周围的多个位置重用操作/减少器?

Have your reducer handle multiple instances of your component state. 让reducer处理组件状态的多个实例。 Simply define some "unique" ID for each instance of your FileBrowser component when it appears in the app, and wrap your current state in an object with this uniqueIds as keys, and your old complex state as value. 简单地为FileBrowser组件的每个实例定义一些“唯一”ID,当它出现在应用程序中时,将当前状态包装在一个对象中,其唯一ID为键,旧复杂状态为值。

This is a technique I've used multiple times. 这是我多次使用的技术。 If all your FileBrowser are known at compile time, you can even setup the initial state before running your app. 如果在编译时知道所有FileBrowser,您甚至可以在运行应用程序之前设置初始状态。 If you need to support "dynamic" instances, simply create an Action that initializes the state for a given id. 如果需要支持“动态”实例,只需创建一个初始化给定id的状态的Action。

You didn't provide any code, but here's a contrived example for a reusable Todo reducer: 你没有提供任何代码,但这是一个可重复使用的Todo减速器的人为例子:

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 ]
         }
      }
      // ... 
  }
}

Usually, the rule of thumb is that you use a redux store to manage data in your application aka storing items fetched from the server and local react state for ui behaviors, like file uploads in your case. 通常,经验法则是您使用redux store来管理应用程序中的数据,即存储从服务器获取的项目以及ui行为的本地react state ,例如您的案例中的文件上载。 I'd make a pure react component to manage file uploads and then use redux-form to manage specific form. 我会制作一个纯粹的反应组件来管理文件上传,然后使用redux-form来管理特定的表单。

Here is the example of the component I use in my project 以下是我在项目中使用的组件示例

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;

We came to the conclusion that reusable components must be of two kinds: 我们得出结论,可重用组件必须有两种:

  • dumb components, ie components that only receive props and trigger "actions" via props callbacks only. 哑组件,即仅接收道具并仅通过道具回调触发“动作”的组件。 These components have minimal internal state or at all. 这些组件具有最小的内部状态或根本没有。 These are the most frequent of reusable components, and your file selector will probably fall in that case. 这些是最常见的可重用组件,在这种情况下,您的文件选择器可能会出现问题。 A styled Text Input or custom List would be good examples too. 样式化的文本输入或自定义列表也是很好的例子。

  • connected components that provide their own actions and reducer. 连接的组件,提供自己的操作和reducer。 These components have their own life within the application and are rather independent from the rest. 这些组件在应用程序中有自己的生命,并且与其他组件相互独立。 A typical example would be a "top error message box" that displays on top of everything else when the application fails critically. 一个典型的例子是“顶部错误消息框”,当应用程序严重失败时,它会显示在其他所有内容之上。 In such a case the application triggers an "error action" with the appropriate message as payload and on the following re-render, the message box displays on top of the rest. 在这种情况下,应用程序触发“错误操作”,并将相应的消息作为有效负载,并在随后的重新呈现中,消息框显示在其余部分之上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM