It's quite a bit of work since it's 2 different frameworks. The codebase on gatsby was under-maintained, so it was a bit painful to upgrade the packages.
I left out some of the features to be worked/not worked on next:
Since the latest version encourage App Router
, so I went for it as well. However, the documentation is pretty much mixed up with old Page Router
, so it made it a bit difficult to find which part works for which part.
# changes from pages/ to
app/[slug]/
page.js
app/components/
[component-name].js
I want to keep SSG of Gatsby in Next.js, so the design/steps I took should follow the direction as well.
Since I want to prerender my photos from Sanity.io, so using it along with Server Components
is a must.
React Server Components was introducted to enable server side rendering. By default Next.js will render the components as server components
, unless otherwise stated e.g., "use client"
on top of the files.
This gives many warnings/errors when I first moved the components
over. so basically, any components that uses useState
, useLayout
, Context
will be flagged.
server components
and client components
props
from server components
and client components
For example:
server components
cannot be imported and used in client components
.'use client'
export default function ClientComponent({children}) {
const [count, setCount] = useState(0)
return (
<>
<button onClick={() => setCount(count + 1)}>{count}</button>
<ServerComponent />
</>
)
}
Server Components
can be rendered inside child components with the use of composition.export default function Page() {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
)
}
The idea is to encourage a new structure/rule of thumbs where server components
are kept in the upstream, client components
in the downstream.
Some refactoring was done:
Differentiate and isolate the components from top down, "delay" and start making server components until it cannot be done, then set child components as client components (e.g., "use client"). Basically I tried first not use any useState
, useEfect
, useLayoutEffect
in the server components
, refactor them and use them later in the client components
.
Problem came when it creates a gap between client components
when we cannot just pass the e..g.,props.setPreviewItem
to the other component. That's when React Context API
came in to help. It looks like this
"use client";
export const ClientComponent = ({ children }) => {
return (
<section>
{/* children is server components that consist of other client components */}
<PreviewContext.Provider>{children}</PreviewContext.Provider>
</section>
}
I need to convert Gatsby
query into GROQ
language for Sanity.io, then use this in the server components
, no more getStaticProps
. e.g., const albums = await getAlbums()
.
// Instantiate Sanity.io client
const client = createClient({
token: process.env.NEXT_PUBLIC_SANITY_TOKEN,
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
useCdn: true, // `false` if you want to ensure fresh data
});
// getAlbums by querying client with GROQ
export async function getAlbums() {
const query = `*[_type == "album"]{
_id,
title,
photos[]{
"assetId": asset->_id,
"originalFilename": asset->originalFilename,
"width": asset->metadata.dimensions.width,
"height": asset->metadata.dimensions.height
}
}`;
try {
const data = await client.fetch(query, { cache: "force-cache" });
return data;
} catch (err) {
return [];
}
}
// Extract url for use in img.src
import imageUrlBuilder from "@sanity/image-url";
const builder = imageUrlBuilder(client);
// Usage: urlFor(assetId).width(width).height(height).url()
export function urlFor(source) {
return builder.image(source);
}
// next.config.js
const nextConfig = {
output: "export", // export as static files
images: {
unoptimized: true, // "output: export" do not support optimized image
remotePatterns: [ // allowing remote image urls
{
protocol: "https",
hostname: "cdn.sanity.io",
port: "",
pathname: `/images/**`,
},
],
},
};
Created 2023-12-09T20:49:38+08:00, updated 2024-08-15T17:54:59+02:00 · History · Edit