【问题标题】:Resuable component with internal, isolated Redux store具有内部隔离 Redux 存储的可重用组件
【发布时间】:2016-08-30 05:36:51
【问题描述】:

我正在考虑在 React 中构建一个非常复杂的图表组件,并且我希望它可以在许多不同的项目中重复使用。不用说,像这样的组件有许多需要以某种方式管理的状态。

Redux 似乎非常适合这种情况,但是如果我只是将顶级容器包装在具有自定义存储的 Provider 中...如果包含组件,组件的内部 redux 存储不会干扰全局应用程序状态在更大的 React/Redux 应用程序中?

import React, { Component } from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import internalReducer from './reducer';

export default class MyReduxComponent extends Component {

    render() {
        const store = createStore(internalReducer, this.props.initialState);
        return <Provider store={store}>
            <Chart />
        </Provider>
    }

}

【问题讨论】:

    标签: reactjs redux react-redux


    【解决方案1】:

    你的组件不应该有自己的内部 redux 存储,而应该有自己的 reducer + 动作/动作创建者,reducer 知道,所以它可以很容易地与现有的 redux 应用程序集成:

    import { chartReducer, chartActionCreators } from 'your-chart'
    
    combineReducers({
      ...global.stuff,
      chartReducer
    })
    
    store.dispatch(chartActionCreators.action())
    
    --
    
    import Chart from 'your-chart'
    
    export default () =>
      <div>
        <Chart />
      </div>
    

    您库的用户可能不需要显式使用任何操作,只需包括 reducer 就足够了,因此可以在应用程序的任何位置访问图表状态。

    此外,如果您需要以某种方式增加操作调用,您可以编写一些中间件。

    http://redux.js.org/docs/advanced/Middleware.html

    【讨论】:

    • 我也是这么想的,但是那我的组件对不使用redux的人来说就没用了?
    • 这不一定是真的......这真的取决于你如何实现它。如果还没有可用的 redux 商店,您可以回退到您自己的 redux 商店,您可以回退到 this.state,您可以导出图表的多个版本.. 这里有很多可能性,但在已经存在的情况下一个 redux,嵌套一个并不是一个好主意,因为 connect 会查看不同的提供者。
    • 另外......redux 已成为通量标准......它甚至是 facebook 正确的 github 帐户的一部分。我认为可以肯定地说,制作一个 redux-chart 库将受到高度赞赏(如果没有现有的库)
    • 好点!我想在决定如何处理状态时,我必须让组件变得更聪明。
    【解决方案2】:

    你不只是使用 React 组件状态有什么原因吗? Redux 旨在用于需要由整个应用程序中的多个组件访问的状态。如果您要管理的状态仅供特定组件的后代使用,那么您也可以只使用组件状态——在这种情况下不需要 Redux。这样,您的组件将更加可重用,并且不会依赖额外的依赖项。

    【讨论】:

    • 是的,但是想象一下该组件由 14 个不同的子组件组成,它们都需要了解彼此的状态。这很快就会变得一团糟。
    • 主要的顶级图表组件将管理需要在其后代之间共享的状态。这些后代可以通过道具访问/更改该状态。后代组件本身不会持有任何共享状态。这种方法不会比尝试使用某种嵌入式 Redux 更麻烦,而且更符合预期用途。
    • 我认为你是对的。如果有人偶然发现这个问题,我会用原型创建一个答案。
    • 我有同样的 iea @hampusohlsson。在具有大量状态的基于画布的可视化上工作,在添加一定数量的状态后,可读性确实成为一个问题。 Redux 子应用程序似乎是正确的方法。你会推荐组件状态/钩子或 redux 子应用方法吗?
    • @HimanshuChhabra 我在 5 年前问过这个问题,此后发生了很多事情。今天肯定会采用 state/hooks 方法来保持组件内部的状态
    【解决方案3】:

    我想我找到了一个很好的方法来解决这个问题,在顶部组件中使用 childContextTypes 和 setState。这允许任何深度的子组件只“导入”他们需要的上下文操作。 (这消除了通过多个嵌套组件将回调作为 props 传递的需要)。

    Example on JSBin

    顶级组件可能如下所示

    export default class ReusableComponent extends Component {
    
      // Define the public API interface to child components
      static childContextTypes = {
        // expose component state store
        store: PropTypes.object,
        // actions
        setFoo: PropTypes.func,
        setBar: PropTypes.func
      };
    
      // Set initial state, can be overriden by props
      constructor(props) {
        super(props)
        this.state = {
          foo: 'My Foo',
          ...props
        }
      }
    
      // Define methods for public API 
      getChildContext() {
        return {
          store: this.state,
          setFoo: this.setFoo.bind(this),
          setBar: this.setBar.bind(this)
        };
      }
    
      // Reducer for action setFoo
      setFoo(foo) {
        this.setState({ foo })
      }
    
      // Just render components, no need for passing props
      render() {
        return <div>
          <UpdateFooComponent />
          </div>
      }
    
    }
    

    还有一个子组件

    class UpdateFooComponent extends Component {
    
      // 'import' the store and actions you need from top component
      static contextTypes = {
        store: PropTypes.object,
        setFoo: PropTypes.func
      };
    
      clickHandler(e) {
        this.context.setFoo('Hello from subcomponent');
      }
    
      render() {
        const { foo } = this.context.store;
        return <div>
          <button onClick={::this.clickHandler}>Update foo</button>
          <p><strong>foo:</strong> {foo}</p>
        </div>
      }
    
    }
    

    【讨论】:

    • 这当然可以。上下文类似于全局变量,因此应该尽可能避免使用它。例如,在这种情况下,您在 ReusableComponent 中定义了一个“存储”上下文 - 如果使用此组件的任何人也在使用 react-redux,则会发生冲突,因为来自 react-redux 的 Provider 组件也定义了一个“存储”语境。此外,您可能知道,上下文仍被认为是实验性的,因此 API 可能会在未来发生变化。
    • 对...嗯。因此,您会说最好的方法是将 所有内容 作为 props 传递,即使这意味着将 props 发送给不使用它们的组件,而不是将它们传递给它们的子组件?
    • 这应该是您的默认选择。如果通过组件传递 props 变得很麻烦,那么您可能需要考虑在上下文的便利性和它的缺点之间进行权衡。不过,几乎总能找到一个优雅的解决方案,使用 props 可以更轻松地跟踪通过组件的数据流。有关此主题的一些“上下文”(tee hee),请查看 Dan Abramov(Redux 的创建者)关于在 react-redux 中使用上下文的答案:stackoverflow.com/questions/36428355/…
    • 你能不能直接在你的图表组件顶部放置一个容器组件来直接访问状态/存储?对于您的操作,您不需要将它们传递下去,因为它们会被您在顶部注册的减速器拾取。
    猜你喜欢
    • 2020-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    相关资源
    最近更新 更多