【问题标题】:ReactJs - Reuseable Redux ServiceReactJs - 可重用的 Redux 服务
【发布时间】:2016-01-11 01:13:15
【问题描述】:

我了解 Redux 的操作、reducer 和映射到存储的概念。 我已经能够成功地将 Redux 执行到我的应用程序中。

我一直在愉快地使用 React 的 contextTypes 来处理需要来自 Redux 的数据的子组件,这些数据之前已被调用过。

然后我遇到了一个奇怪的情况,数据被一个孩子变异了。当我在 SO 上发布问题时,一位成员告诉我无论如何我都应该谨慎使用 contextTypes。

所以解决我的问题的唯一方法是在孩子的父母中再次映射到商店,就像父母的更高组件之前所做的那样,并将该数据作为道具传递给孩子.

但这对我来说似乎完全错了。再次映射到同一家商店?为什么?我不明白什么?为什么我必须在每个需要另一个组件映射到的相同数据的组件上写这个?

  export default class Foo extends Component {        

  .....

  // I DID THIS STUFF IN A HIGHER COMPONENT.
  // WHY MUST I REPEAT MYSELF AGAIN?
  // WHAT AM I NOT UNDERSTANDING?

  static propTypes = {
    children: PropTypes.node.isRequired,
    dispatch: PropTypes.func.isRequired,
    products: PropTypes.array
  };

  componentDidMount() {
    const { dispatch } = this.props;  
    dispatch(fetchProductsIfNeeded());
  }

  .....

 }  

const mapStateToProps = (state) => {
  const {productsReducer } = state;
  if (!productsReducer) {
    return {
      isFetching: false,
      didInvalidate: false,
      error: null,
      products: []
    };
  }

  return {
    error: productsReducer.error,
    isFetching: productsReducer.isFetching,
    didInvalidate: productsReducer.didInvalidate,
    products: productsReducer.products
  };
};

export default connect(mapStateToProps)(Foo);

我查看了容器,但在我看来容器将所有愚蠢的组件一次包装在其中......

   <ProductsContainer>
      <ProductsComponent />
      <ProductSpecialsComponent />
      <ProductsDiscountedComponent />
   </ProductsContainer>

这不是我想要的。我想,就像服务一样,我可以在每个相应的哑组件中使用该容器......

   <ProductsContainer>
      <ProductsDiscountedComponent />
   </ProductsContainer>

   <ProductsContainer>
      <ProductSpecialsComponent />
   </ProductsContainer>

   <ProductsContainer>
      <ProductsComponent />
   </ProductsContainer>

现在为了获得上面所示的 3 个子组件,它们中的每一个都必须映射到商店,而这似乎完全错了。

我找不到任何我可以掌握的解决方案。

问题:

有没有一种方法可以只映射一次,然后为需要该数据的组件调用该“服务”?

如果是这样,我们将不胜感激。

后记:

我虽然也许如果我可以将“映射服务”作为一个纯 JavaScript 函数 o/s 执行,并将该函数导入需要它的组件中,这将解决问题,但我还没有看到任何Redux 存储被映射到 o/s React 的示例。

更新:

我在这里发布了解决方案......

React-Redux - Reuseable Container/Connector

【问题讨论】:

标签: javascript reactjs redux


【解决方案1】:

首先,谈谈你过去的问题。确实,上下文不适合这样的事情。您还应该担心您提到的突变。如果您使用的是 Redux 存储,则退出它的数据应该始终是不可变的。也许像Immutable.js 这样的库会有所帮助。


现在让我们转向手头的问题。也许您没有完全理解的是“哑”组件是什么。哑组件应该是无状态的并且是纯的:

const Product = ({ name, comments }) => (
  <div>
    <h1>{name}</h1>
    <CommentsList comments={comments} />
  </div>
);

组件从 props 中获取所需的一切。现在有很多方法可以将数据获取到这个组件中,但它们都是基于 props 的。例如,以下是最直接的:

const ProductList = ({ products }) => (
  <div>
    {products.map( p => <Product product={product} /> )}
  </div>
);

class App extends Component {
  getInitialState () {
    return { products: [] };
  }

  componentDidMount () {
    // connect to store, blah blah...
  }

  render () {
    return (
      <div>
        {/* blah blah */}
        <ProductsList products={this.state.products} />
        {/* blah blah */}
      </div>
    );
  }
}

从示例中可以看出,整个组件树将从简单地从一个连接传递到商店的道具中获取其状态。除了App,所有组件都是哑的、无状态的和可预测的。

但在某些情况下,通过道具连接整个树是不切实际的,我们需要本地连接到我们的商店。这就是 HOC 可以大有帮助的地方:

const WithProducts = Comp => class WrappedComponent extends Component {
  getInitialState () {
    return { products: [] };
  }

  componentDidMount () {
    // connect to store, blah blah...
  }

  render () {
    return (
      <Comp products={this.state.products} {...this.props} />
    );
  }
}

const ProductListWithProducts = WithProducts( ProductList );

现在我们这样包装的任何组件都将从商店接收产品列表作为道具 - 无需重复代码。不重复自己。请注意,我是如何没有更改 ProductListProduct 组件来完成这项工作的:这些组件太笨了,无法在意。

您创建的任何 React 应用程序中的大多数组件都应该是非常愚蠢的。


另外,您应该不要担心多次致电您的商店。如果您担心这一点,那么存储实现存在问题,因为对存储的调用应该是幂等的。您可以使用操作等来填充商店,但这应该完全独立于从商店获取值。设计良好的存储检索不应该有性能或网络损失(同样,使用 Immutable 之类的库也可以提供帮助)。

【讨论】:

  • 首先,感谢您的帮助。我和你们一起跟着cmets。是的,我知道什么是愚蠢的组件,但是我不能再一次用道具填充每个祝福的组件,因为第 N 代孩子需要这些道具。我假设“ProductListWithProducts”是“服务”。我如何在哑组件上实现它?
  • ProductListWithProducts 是一个复合 组件。它呈现哑组件ProductList,但通过添加存储功能扩展它。正如我在上面写的,它已经在哑组件上实现了。哑组件从不改变。一旦这样做,它就不再愚蠢了。但我仍然要注意,每次使用WithProducts HOC 时,您都会接到商店的电话——这是按照设计的。无论如何,没有像 MVC 中那样的“服务”,我不确定您在这里如何使用该术语。
猜你喜欢
  • 2020-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-14
  • 2020-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多