Say I have a functional React presentation component, like so:

const Functional = (props) => {
  // do some stuff

  return (
    <div>
      // more HTML based on the props
    </div>
  );
}

Functional.propTypes = {
  prop1: React.PropTypes.string.isRequired,
  prop2: React.PropTypes.string.isRequired,
  // ...
};

If I'm using Redux and following the container component pattern, what would be the best way to render a dynamic number of these <Functional/> components inside a wrapper component, based on elements inside a array (which is inside my Redux state)?

E.g. My Redux state might look like this:

{
  functionalItems: [
    {
      prop1: 'x1',
      prop2: 'y1',
      // ...
    },
    {
      prop1: 'x2',
      prop2: 'y2'
    },
    // ... more items
  ],
  // ...
}

So each item in the functionalItems array should correspond to a <Functional/> component, which all get rendered adjacent to each other.

This is the second time I have come across this problem, so I'm hoping that it's common enough that there is good solution out there.

I'll post the solutions I can come up with (but which have undesirable traits), as answers to this question.

2

There are 2 answers

9
JD Hernandez On BEST ANSWER

I'd like to suggest that you pass the entire array to the wrapper component like this:

const mapStateToProps = (state) => ({
    items: getFunctionalItems(state),
    // ...
});

and then in your Wrapper.jsx, do it like this:

const Wrapper = (props) => {

  const elements = props.items.map((item, index) => {
    <Functional prop1={ item.prop1 } prop2={ item.prop2 } ...
      key={ ... /* you can use index here */ }/>
  });

  return (
    <div>
      { elements }
    </div>
  );

};

...where getFunctionalItems() is an accessor function that is the canonical means of accessing the functional items from the state.

This way, you can handle changes in state structure, or a different rendering layout. (ergo more robust (I think)). And it looks more like following the Single Responsibility Principle.

1
pleasedesktop On

Solution Description

  • Create a wrapper functional presentation component that takes in a quantity and functions to fetch the <Functional/> prop values.
  • Create a container component that connects to this new wrapper component and passes in the quantity (based on the Redux state) and accessor functions to fetch the <Functional/> prop values.

Example Code

Wrapper.jsx:

const Wrapper = (props) => {

  const elements = [];

  for (let i = 0; i < props.quantity; i++) {
    elements.push(
      <Functional prop1={ getPropValue1(i) } prop2={ getPropValue2(i) } ...
                  key={ ... }/>
    );
  }

  return (
    <div>
      { elements }
    </div>
  );
};

Wrapper.propTypes = {
  quantity: React.PropTypes.number.isRequired,
  getPropValue1: React.PropTypes.func.isRequired,
  getPropValue2: React.PropTypes.func.isRequired,
  // ...
};

ContainerComponent.js:

const mapStateToProps = (state) => ({
  quantity: state.functionalItems.length,
  getPropValue1: (index) => state.functionalItems[index].prop1,
  getPropValue2: (index) => state.functionalItems[index].prop2,
  // ...
});

const ContainerComponent = connect(mapStateToProps)(Wrapper);