4

Code Situation

I have a simple react app setup. The home component should be a image gallery with a masonry layout. I found this library: Bricks.js I load the data (name, date, url to image) of the items from my api with fetch.

Here are some parts of my code in Home.js:

The constructor()

constructor() {
  super();
  this.state = {
    galleryItems: []
  };
  this.instance = {}
}

This function loads the data of the items.

getItems(limit){
  fetch('http://localhost:3000/api/posts/next/' + limit)
    .then((response) => {
      return response.json()
    }).then((data) => {
      this.setState({galleryItems: data});
    })
}

I used the componentDidMount() function to load 5 items and create the Bricks.js instance.

componentDidMount(){
  this.getItems(5)
  //sizes for Brick.js
  const sizes = [
    { columns: 5, gutter: 3 },
    { mq: '768px', columns: 2, gutter: 3 },
    { mq: '1024px', columns: 3, gutter: 3 }
  ]
  //init instance
  this.instance = Bricks({
    container: '.gallery',
    packed: 'packed',
    sizes: sizes
  })
  this.instance.resize(true);  //<-adds a resize event listener
  if (this.state.galleryItems.length > 0) {
    this.instance.pack() //<- This should create the masonry layout
  }
}

And for loading more image I wrote this in the componentDidUpdate() function.

componentDidUpdate(){
  if (this.state.galleryItems.length > 0) {
    return this.instance.pack()
  }
  else{
    return this.instance.update() //<- updates the layout
  }
}

The render() function converts the data from the server to a <Item> which is just another component that creates a <img> element

render() {
  const items = this.state.galleryItems.map((item, _id) => {
    return <Item key={_id} url={this.state.url + item.url}></Item>
  })
  return (
    <div>
      Home Component
      <div className="gallery">
        {items}
      </div>
    </div>
  );
}

Problem

If I open my app in firefox it works fine. But in chrome the images are just on top of each other. If I resize the window the masonry layout is created fine. I seems chrome is either too fast or slow. What is wrong with my code that this can happen?

Community
  • 1
  • 1
Colin
  • 1,112
  • 1
  • 16
  • 27
  • I was having a really similar issue because I was fetching items from my server that contained iframes. The component would load faster than the iframes could render, so the Masonry component couldn't get an accurate height of all the items in time (resulting in a height too small; this makes the images fall on top of each other). What ended up helping me was rerendering the component once all the items I fetched loaded. – bwalshy Jun 12 '17 at 14:57
  • @bwalshy So a solution/workaround would be to store the sizes of the images and create a div with the correct sizes first so the images could load into the framing div? – Colin Jun 12 '17 at 15:17
  • Hmm that might work? But that's also a lot of calculating. I meant waiting for all the images to load, then trigger a re-render on the masonry component. That way when the masonry component re-renders, it has the accurate height of all the images inside it. First test if it will even work by in componentDidMount(), add setTimeout(this.forceUpdate, 5000); That will tell the component to update after 5 seconds (hopefully all the images would have loaded by then). If that fixes your problem, then you find a way to detect if all the images loaded and if it did, rerender the component – bwalshy Jun 12 '17 at 15:27

0 Answers0