5 Essential Tips and Tricks for Mastering Next.js
Tags: webdev, nextjs, react, beginners
Published: 2024-06-09 04:28:29

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:**
```jsx
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:
```bash
npm install sharp placeholder
```

2.Create a utility function:
```jsx
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:
```jsx
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:**
```env
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:**
```jsx
// 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:**
```jsx
// 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.

```jsx
// 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:**
```jsx
// 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:**
```jsx
// 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.