React-Redux - 可重复使用的容器/连接器

时间:2016-01-15 18:42:58

标签: reactjs reactjs-flux redux

我完全迷失在react-redux容器(即连接器)概念上,因为它没有按照我的预期行事。我的问题是直截了当的,对我来说是合理的,但我找不到一个如何实现它的写得很好的例子。

我们假设有一个react组件连接到具有产品上下文的商店,我们将调用此组件ProductContext

此外,我们想要在整个应用程序中自由地重用ProductContext,以避免在可能需要产品的每个其他组件上调度操作的样板代码。

说明这就是我的意思:

来自DiscountuedProducts的

<ProductContext >
   // do something with props from container
</ProductContext >
来自SeasonalProducts的

<ProductContext >
   // do something with props from container
</ProductContext >

从我在react-redux看到的例子来看,在我看来,他们的容器将容器本身的季节性和停产产品混为一谈。那怎么可重复使用?

来自ProductContextComponent的

<section >
  <DiscontinuedProducts />
  <SeasonalProducts />
</section >

使事情变得复杂,同时试图对这个最令人沮丧的问题保持冷静,并且#34;模糊不清的&#34;似乎是我收到的唯一回复。

所以这是我的ProductContext

@connect(state => ({
   products: state.productsReducer.products
}))
export default class ProductContext extends Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const { dispatch } = this.props;
    const clientId = this.context.clientInfo._id;
    dispatch(fetchProductsIfNeeded(clientId));
  }

 // get from parent
 static  contextTypes = {
    clientInfo: PropTypes.object.isRequired
  };

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


  render() {
    if (!this.props.products) return <Plugins.Loading />;
    .....
    return (
         // I want to put the products array here
      );
    }
 };

然后我的想法是,如果我这样做:

来自DiscountuedProducts的

<ProductContext >
   // do something with props from container
</ProductContext >

DiscontinuedProducts应该了解这些产品,并且可以简单地过滤已停产的产品。

我对此完全错了吗?欲望这是不合理的吗?

如果有人知道网上有一个详尽的示例,说明如何实现这一目标,我将非常感谢它向我指出。我已经花了一个多星期来解决这个问题,并准备放弃react-redux。

更新:以下使用HOC的解决方案。

2 个答案:

答案 0 :(得分:1)

  

如果有人知道网上有一个详尽的例子,说明如何实现这一点,我将非常感谢它被指出给我。

查看Shopping Cart example

示例代码来自:shopping-cart/containers/CartContainer.js

  

让我们说我们有一个反应组件连接到具有产品上下文的商店

产品 商店,用户等商店等。所有商品都有一商店。您应该使用reducer来获取完整存储并减少组件所需的内容。

来自示例:

import { getTotal, getCartProducts } from '../reducers'

const mapStateToProps = (state) => {
  return {
    products: getCartProducts(state),
    total: getTotal(state)
  }
}

这里是整个商店。

  

让我们说我们希望在整个应用程序中大量重用ProductContext,以避免调度操作的样板代码

组件不会调度操作,它们会调用传递给它们的函数。这些函数位于一个动作模块中,您可以将其导入并作为道具传递给容器。反过来,容器将这些函数传递给组件道具。

来自示例:

import { checkout } from '../actions'

CartContainer.propTypes = {
  checkout: PropTypes.func.isRequired
}

connect(mapStateToProps,
  { checkout }
)(CartContainer)

连接做什么,它订阅商店更改,调用地图功能,与常量道具合并(这里是动作功能),并为容器分配新道具。

  

DiscontinuedProducts应该了解这些产品,并且可以简单地过滤已停产的产品

这实际上就是现货。你提到的知识一个商店,它绝对应该在reducer中过滤。

希望这可以解决问题。

答案 1 :(得分:0)

我找到了一种更实用的方法来利用来自redux的重复数据而不是文档。如果我已经在更高级别完成了一次,那么重复mapToProps并在每个有福的组件上调度实例化是没有意义的,并且存在解决方案。确保您的应用符合Babel 6标准,因为我使用了装饰器。

<强> 1。我为上下文创建了一个更高阶的组件....

<强>产品context.js

   import React, { Component, PropTypes } from 'react';
   // redux
   import { connect } from 'react-redux';
   import { fetchProductsIfNeeded }  from '../../redux/actions/products-actions';
    // productsReducer is already in state from index.js w/configureStore
    @connect(state => ({
      products: state.productsReducer.products
    }))
   export default function ProductContext(Comp) {
    return (
      class extends Component {
        static propTypes = {
          children: PropTypes.node,
          dispatch: PropTypes.func.isRequired,
          products: PropTypes.array
        };

        static contextTypes = {
         clientInfo: PropTypes.object.isRequired;
        };

        componentDidMount() {
          const { dispatch } = this.props;
          const clientId = this.context.clientInfo._id;
          dispatch(fetchProductsIfNeeded(clientId));
        }

        render() {
          if (!this.props.products) return (<div>Loading products ..</div>);
          return (
            <Comp products={ this.props.products }>
              { this.props.children }
            </Comp>
          )
        }
      }
    )
  }

<强> 2。组件利用product-context.js

<强>转盘-slider.js:

import React, { Component, PropTypes } from 'react';
......
import ProductContext from '../../../context/product-context';
@Radium
@ProductContext 
export default class CarouselSlider extends Component {

  constructor(props) {
    super(props);   }

  ......

  static showSlideShow(carouselSlides) {
    carouselSlides.map((slide, index) => {
       ......          
     results.push (
       ......
      )
    });
    return results;   
  }

  render() {
    const carouselSlides = this.props.products;
    const results = CarouselSlider.showSlideShow(carouselSlides);
    return (
      <div id="Carousel" className="animation" ref="Carousel">
        { results }
      </div>
    );   
  } 
}

所以你去吧。我需要的只是装饰器对产品上下文的引用,作为HOC,它返回带有产品prop的carousel组件。

我为自己保存了至少10行重复代码,并从较低的组件中删除了所有相关的contextType,因为使用装饰器不再需要它。

希望这个真实世界的例子有所帮助,因为我讨厌这些例子。