3

I have a list of 8 images that I want to render in a grid:

----- ----- ----- -----
|   | |   | |   | |   |
|   | |   | |   | |   |
----- ----- ----- -----
----- ----- ----- -----
|   | |   | |   | |   |
|   | |   | |   | |   |
----- ----- ----- -----

I do it with Bootstrap 3: rows and columns

<div className="row">

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>
</div> <!-- END row -->

<div className="row">

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>

    <div className="col-xs-3">
        <img src="..." alt="..." />
    </div>

</div> <!-- END row -->

So I need to loop through the list and for each 4 images I need to wrap them in a row. This serves as a spacer (20px) between rows.

In normal JS I would concatenate a string of markup while looping and using the iterator index as a condition. But I can't do this in JSX as I understand.

So how do I do this with JSX?

olefrank
  • 6,452
  • 14
  • 65
  • 90
  • I think I see the issue. You'll need to group all the images into arrays of 4, iterate over the group array, and inside the group iterate over the images. – Swimburger Mar 24 '17 at 21:15
  • Don't forget to upvote/accept if one of the answers solved your question. – Swimburger Mar 27 '17 at 12:58

2 Answers2

2

First you need to group your images by 4. You can use the groupBy function below. It basically slices your images-array into groups of 4. Next you need to iterate over your groups to create a row per group. Then inside the group, you need to iterate over the images, column per image.

var images = ["https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/","https://baconmockup.com/300/200/"];
function render(){
  var imageGroups = groupBy(4, images);
  return (<div>
            {imageGroups.map(renderRow)}
          </div>);
}

function renderRow(group, index){
  return (<div className="row" key={index}>
            {group.map(renderColumn)}
          </div>);
}

function renderColumn(image, index){
  return (<div className="col-xs-3" key={index}>
            <img src={image} />
         </div>);
}

function groupBy(amountOfItemsPerGroup, items){
  var groups = [], 
    group, 
    total = items.length;
  for (var i=0; i < total; i += amountOfItemsPerGroup) {
    group = items.slice(i, i+amountOfItemsPerGroup);
    groups.push(group);
  }
  return groups;
}

ReactDOM.render(
  render(),
  document.getElementById('root')
);

See jsbin

Swimburger
  • 6,681
  • 6
  • 36
  • 63
  • For some reason jsbin is buggy with jsx, you may have to refresh the browser few times, or run with js few times. – Swimburger Mar 24 '17 at 22:19
  • Good suggestion but I dont think that I can use it because I need to animate the list when items are added and removed. I wrap "grouped" lists in a ReactCSSTransitionGroup component. But problem is that im not added/removing from the grouped list but from the one in state... So react doesn't notice any changes and therefore nothing is animated... – olefrank Mar 27 '17 at 14:33
  • That's too bad, I hope you find a solution with transitions working. – Swimburger Mar 27 '17 at 14:35
  • I will look into react-motion soon. That seems like a good route for animations in react :) – olefrank Mar 27 '17 at 14:37
0

I think, You do not need two row. Bootstrap will auto move 5th image to next line. Instead you should clearfix class.

    let arr = [1,2,3,4,5,6,7,8];
     let rows= [];
         arr.forEach((val,index)=>{
        rows.push(<div key={index} className="col-xs-3">
            <img src="..." alt="..." />
        </div>
  })

    <div className="row">
    {
     rows
    }

 </div>
Ved
  • 11,837
  • 5
  • 42
  • 60
  • No it can be necessary because the cols are floated. Read more here: http://stackoverflow.com/questions/26441689/if-more-than-12-columns-wrap-onto-a-new-line-automatically-do-we-really-need-to/26445839#26445839 – olefrank Mar 24 '17 at 21:23