Replies: 3 comments 2 replies
-
|
Unfortunately, there is no perfect solution to this problem in the current version of this library since components that depend on viewport size are inherently at odds with SSR. Here are some workarounds that may be appropriate depending on your use case.
<PhotoAlbum
layout="rows"
photos={photos}
breakpoints={[600, 900, 1200]}
defaultContainerWidth={300}
/>
const useLayoutEffect = typeof document !== "undefined" ? React.useLayoutEffect : React.useEffect;
const SSRPhotoAlbum = ({ layout, photos }) => {
const [mounted, setMounted] = React.useState(false);
useLayoutEffect(() => {
setMounted(true);
}, []);
return (
<PhotoAlbum
layout={layout}
photos={photos}
componentsProps={!mounted ? { containerProps: { style: { visibility: "hidden" } } } : undefined}
/>
);
};The ultimate "solution" is quite elaborate and resource intensive (or you could say wasteful). The idea is to define N breakpoint intervals, render N photo albums for each interval, hide each photo album via CSS outside its corresponding breakpoint interval, and then swap all that mess with a single photo album after hydration. It's messy but doable, and I'll share a draft later. p.s. I will also explore server components when they become stable in Next.js. |
Beta Was this translation helpful? Give feedback.
-
|
As promised, I'm sharing a draft of the "ultimate solution" for future reference. This example is built specifically for Next.js SSR. I'm sure it will be overkill for most users, but feel free to use it if you must have zero CLS in SSR, and performance penalties are not a concern. const useLayoutEffect = typeof document !== "undefined" ? React.useLayoutEffect : React.useEffect;
const SSRPhotoAlbum: React.FC<
Omit<PhotoAlbumProps, "breakpoints" | "defaultContainerWidth"> &
Required<Pick<PhotoAlbumProps, "breakpoints">> & { viewportBreakpoints: number[] }
> = ({ breakpoints, viewportBreakpoints, componentsProps, ...rest }) => {
const [mounted, setMounted] = React.useState(false);
useLayoutEffect(() => setMounted(true), []);
const allBreakpoints = [breakpoints[0] / 2].concat(breakpoints);
const allViewportBreakpoints = [0].concat(viewportBreakpoints);
if (!mounted) {
const styles = allViewportBreakpoints
.flatMap((breakpoint, index, array) => [
`.react-photo-album-ssr-${breakpoint} { display: none }`,
`${
index < array.length - 1
? `@media (min-width: ${breakpoint}px) and (max-width: ${array[index + 1] - 1}px)`
: `@media (min-width: ${breakpoint}px)`
} { .react-photo-album-ssr-${breakpoint} { display: flex } }`,
])
.join("\n");
return (
<>
{/* eslint-disable-next-line react/no-unknown-property */}
<style jsx global>
{styles}
</style>
{allViewportBreakpoints.map((breakpoint, index) => (
<PhotoAlbum
key={breakpoint}
breakpoints={breakpoints}
defaultContainerWidth={index > 0 ? breakpoints[index - 1] : breakpoints[0] / 2}
componentsProps={(w) => {
const originalComponentProps =
typeof componentsProps === "function" ? componentsProps(w) : componentsProps;
return {
...originalComponentProps,
containerProps: {
...originalComponentProps?.containerProps,
className: `react-photo-album-ssr-${breakpoint}`,
style: { display: undefined },
},
};
}}
{...rest}
/>
))}
</>
);
}
const viewportWidth = window.innerWidth;
const breakpointIndex = allViewportBreakpoints.findIndex(
(breakpoint, index, array) => breakpoint <= viewportWidth || index === array.length - 1
);
return (
<PhotoAlbum
key={allViewportBreakpoints[breakpointIndex]}
breakpoints={breakpoints}
componentsProps={componentsProps}
defaultContainerWidth={allBreakpoints[breakpointIndex]}
{...rest}
/>
);
};Usage example: <SSRPhotoAlbum
layout={layout}
photos={photos}
targetRowHeight={150}
breakpoints={[268, 448, 485, 912, 1312]}
viewportBreakpoints={[300, 480, 768, 1200, 1600]}
/> |
Beta Was this translation helpful? Give feedback.
-
|
This is now supported in v3 - https://react-photo-album.com/documentation#Server-SideRendering(SSR)_SSRComponent |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Is your feature request related to a problem? Please describe.
Hi, may I know is there a way I can fix the layout shift during the hydration for Next JS application? It looks obvious on network throttling.
Describe the solution you'd like
Prevent layout shift for SSR application.
Describe alternatives you've considered
No response
Additional context
or validate via
https://react-photo-album.com/examples/rows
Beta Was this translation helpful? Give feedback.
All reactions