5 Essential Tips and Tricks for Mastering Next.js

Vishal Yadav - Jun 9 - - Dev Community

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope these tips and tricks help clarify some common ambiguities in Next.js.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .