Hello, my gorgeous friends on the internet! In today’s blog, we’re diving into five essential tips and tricks for working with Next.js. There’s still a lot of confusion around topics like caching, rendering client components, and more, so I’m here to give you some valuable insights to make your Next.js development smoother and more efficient.
Now, let’s get into the tips!
Tip 1: Handling Images in Next.js
Local Images
One common area of confusion in Next.js is handling images, particularly the differences between local and remote images.
For local images stored in the public
folder, you don’t need to specify width and height. Next.js will automatically identify these attributes.
Example:
import Image from 'next/image';
import myImage from '../public/ahoy.jpg';
export default function Home() {
return (
<div>
<Image src={myImage} alt="Ahoy" />
</div>
);
}
Remote Images
For remote images, you need to provide additional information such as width, height, and blur data to improve loading performance and avoid content layout shifts.
Example:
To add a blur effect to remote images, use the sharp
and placeholder
packages to generate base64-encoded blur data.
1.Install the packages:
npm install sharp placeholder
2.Create a utility function:
import placeholder from 'placeholder';
import sharp from 'sharp';
export async function getBase64(url) {
const res = await fetch(url);
const buffer = await res.arrayBuffer();
const base64 = await placeholder(buffer);
return base64;
}
3.Use the function in your component:
import { getBase64 } from './utils/getBase64';
export default async function Home() {
const blurData = await getBase64('https://source.unsplash.com/random');
return (
<Image
src="https://source.unsplash.com/random"
width={800}
height={600}
alt="Random"
placeholder="blur"
blurDataURL={blurData}
/>
);
}
Tip 2: Environment Variables
When using environment variables, be mindful of the NEXT_PUBLIC_
prefix. Variables with this prefix are exposed to the browser, making them accessible in client-side code. This is useful for public settings but can be a security risk if used with sensitive information like API keys.
-
Public Variables: Prefixed with
NEXT_PUBLIC_
and exposed to the client. - Private Variables: Not prefixed and kept server-side.
Example:
NEXT_PUBLIC_API_URL=https://api.example.com
API_SECRET_KEY=your-secret-key
Tip 3: Caching in Next.js
Caching behavior in Next.js can be quite different between development and production environments.
Development:
In development, pages refresh dynamically, reflecting changes immediately.
Production:
Next.js tries to render pages as static by default. To control this, use the revalidate
option for incremental static regeneration or force-dynamic
for always fetching fresh data.
Example:
// Revalidate every 5 seconds
export const revalidate = 5;
// Force dynamic data fetching
export const dynamic = 'force-dynamic';
Tip 4: Fetching Data Efficiently
Avoid using API route handlers for fetching data in server components. Instead, fetch data directly in your server components. This approach leverages Next.js optimizations and caching.
Example:
// Direct fetch in a server component
export default async function Home() {
const res = await fetch('https://api.example.com/jokes/random');
const data = await res.json();
return <div>{data.joke}</div>;
}
For reusable fetch logic, create server actions and import them where needed.
// server/getJoke.js
import { server } from 'next/server';
export async function getJoke() {
const res = await fetch('https://api.example.com/jokes/random');
const data = await res.json();
return data;
}
// Home.js
import { getJoke } from '../server/getJoke';
export default async function Home() {
const joke = await getJoke();
return <div>{joke.joke}</div>;
}
Tip 5: Client and Server Components
Understanding the difference between client and server components is crucial. By default, pages are server components, but you can include client components within them for interactivity.
Example:
// Client component
'use client';
import { useState } from 'react';
export default function ClientComponent() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
// Server component
import ClientComponent from '../components/ClientComponent';
export default function Home() {
return (
<div>
<ClientComponent />
</div>
);
}
Providers and Child Components
When wrapping components with providers (e.g., for theming), ensure children are treated correctly as server or client components.
Example:
// theme.js
import { ThemeProvider } from 'styled-components';
export default function Theme({ children }) {
return <ThemeProvider theme={{}}>{children}</ThemeProvider>;
}
// layout.js
import Theme from '../components/theme';
export default function Layout({ children }) {
return (
<Theme>
{children}
</Theme>
);
}
Conclusion
I hope these tips and tricks help clarify some common ambiguities in Next.js.