The problem is that when the images are fetched by the browser the height of the cards change so their position should be recalculated. This is done using the useResizeObserver which creates a resize observer that forces updates to the grid cell positions when mutations are made to cells affecting their height. Now whenever you resize the component it will render correctly. There is another issue in initial render width is 0 so the items aren't positioned correctly. I used windowWidth as a placeholder until width is set.
You can check it here in the docs: https://github.com/jaredLunde/masonic#useresizeobserverpositioner
The asnwer CodeSandbox
The answer:
import React from "react";
import ReactDOM from "react-dom";
import { useWindowSize } from "@react-hook/window-size";
import { Card, CardImg, CardText, CardTitle } from "reactstrap";
import { styles } from "./theme";
import {
useMasonry,
usePositioner,
useContainerPosition,
useScroller,
// import this
useResizeObserver
} from "masonic";
const App = () => {
const containerRef = React.useRef(null);
let [windowWidth, windowHeight] = useWindowSize();
const { offset, width } = useContainerPosition(containerRef, [
windowWidth,
windowHeight
]);
// the width is equal to windowWidth - scroll bar width (17px in chrome)
console.log(width, windowWidth);
const positioner = usePositioner({
// Use windowWidth as a placeholder if container width is 0 which causes positioning problems
// This happens in initial render then width will be used
width: width || windowWidth,
columnGutter: 10
});
// This hook creates a resize observer that forces updates to the grid
// cell positions when mutations are made to cells affecting their height.
const resizeObserver = useResizeObserver(positioner);
const { scrollTop, isScrolling } = useScroller(offset);
return (
<main>
<div>
{useMasonry({
positioner,
scrollTop,
isScrolling,
height: windowHeight,
containerRef,
items: items,
render: NatureCard,
// use it here
resizeObserver
})}
</div>
<Header />
</main>
);
};
const NatureCard = ({
index,
data: { image = "", displayName, description = "Hello", link = "" },
width,
height
}) => (
<Card>
<CardImg src={image} />
<CardTitle tag="h5">{displayName}</CardTitle>
<CardText>{description}</CardText>
</Card>
);
const Header = () => {
// const scrollY = useWindowScroll(5);
return (
<h1>
<span role="img" aria-label="bricks">
</span>{" "}
MASONIC
</h1>
);
};
const items = [
{
image:
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/gettyimages-647727888-master-1506626232.jpg",
displayName: "QUIZ: Has Reese Witherspoon Smooched These Guys On-Screen?"
},
{
image:
"https://ichef-1.bbci.co.uk/news/320/cpsprodpb/97BE/production/_98064883_ikea.jpg",
displayName: "Ikea buys odd jobs firm TaskRabbit"
},
{
image:
"https://cdn.theatlantic.com/assets/media/img/mt/2017/09/ra_3000x3000-4/facebook.jpg",
displayName:
"Radio Atlantic: Russia! Live with Julia Ioffe and Eliot A. Cohen"
},
{
image: "https://i.redd.it/th5enkjgumoz.jpg",
displayName: "Bar"
},
{
image: "https://imgur.com/lvK8Faf.jpg",
displayName:
"'Cancer patient' finds lump was toy traffic cone inhaled in 1977 | UK news"
},
{
image: "https://i.imgur.com/e89Pb8j.gif",
displayName: "It's cool bro, I got this"
},
{
image: "https://i.redd.it/336erdiy5moz.jpg",
displayName: "Reddit"
},
{
image:
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/img-5675-jpg-1506621753.jpg",
displayName:
"Prepare to Geek Out Over This Adorable Game of Thrones Wedding Shower"
},
{
image:
"https://venturebeat.com/wp-content/uploads/2017/03/ShopChat-e1506572472915.jpg",
displayName: "Effective chatbots master conversational size and fit"
},
{
image:
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/gettyimages-647727888-master-1506626232.jpg",
displayName: "QUIZ: Has Reese Witherspoon Smooched These Guys On-Screen?"
},
{
image:
"https://ichef-1.bbci.co.uk/news/320/cpsprodpb/97BE/production/_98064883_ikea.jpg",
displayName: "Ikea buys odd jobs firm TaskRabbit"
},
{
image:
"https://cdn.theatlantic.com/assets/media/img/mt/2017/09/ra_3000x3000-4/facebook.jpg",
displayName:
"Radio Atlantic: Russia! Live with Julia Ioffe and Eliot A. Cohen"
},
{
image: "https://i.redd.it/th5enkjgumoz.jpg",
displayName: "Bar"
},
{
image: "https://i.imgur.com/HjgUCHF.png",
displayName:
"'Cancer patient' finds lump was toy traffic cone inhaled in 1977 | UK news"
},
{
image: "https://i.imgur.com/e89Pb8j.gif",
displayName: "It's cool bro, I got this"
},
{
image: "https://i.redd.it/336erdiy5moz.jpg?4",
displayName: "Reddit"
},
{
image:
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/img-5675-jpg-1506621753.jpg",
displayName:
"Prepare to Geek Out Over This Adorable Game of Thrones Wedding Shower"
},
{
image:
"https://venturebeat.com/wp-content/uploads/2017/03/ShopChat-e1506572472915.jpg",
displayName: "Effective chatbots master conversational size and fit"
},
{
image: "https://i.imgur.com/e89Pb8j.gif",
displayName: "It's cool bro, I got this"
},
{
image: "https://i.redd.it/336erdiy5moz.jpg?4",
displayName: "Reddit"
},
{
image:
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/img-5675-jpg-1506621753.jpg",
displayName:
"Prepare to Geek Out Over This Adorable Game of Thrones Wedding Shower"
}
];
ReactDOM.render(<App />, document.getElementById("root"));