ReactJs - 可重用的Redux服务

时间:2016-01-11 01:13:16

标签: javascript reactjs redux

我理解Redux的操作,缩减器和映射到商店的概念。 我已经能够成功地将Redux执行到我的应用程序中。

我正在快速地使用React的contextTypes来处理需要以前调用过的Redux数据的子组件。

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

因此,克服我的问题的唯一方法是在孩子的父母中映射到商店 AGAIN ,就像父母之前做的更高的组件一样,并将该数据传递给孩子作为道具。

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

  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个子组件,每个组件必须映射到商店,这似乎都是错误的。

我找不到任何可以解决的问题。

问题:

有没有办法可以映射到特定商店一次,并且可以调用#34; service&#34;那些需要这些数据的组件?

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

发布脚本:

我可能是因为我可以执行地图服务&#39;作为一个纯粹的JavaScript函数o / s of react,并且只是在需要它的组件中导入该函数,这将解决问题,但我还没有看到任何Redux存储被映射的示例o / s React。

更新

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

React-Redux - Reuseable Container/Connector

1 个答案:

答案 0 :(得分:1)

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

现在让我们转向手头的问题。也许你并不完全是一个“愚蠢”的组成部分。一个愚蠢的组件应该是无国籍的和纯粹的:

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

该组件从道具中获取所需的一切。现在有很多方法可以将数据导入到这个组件中,但它们都基于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这样的库也可以在这里帮助。)