Next.js 新手常見錯誤


哈囉各位開發者朋友們!今天我們要來聊聊 Next.js 這個超強大的 React 框架。雖然它很棒,但對新手來說,還是有一些常見的陷阱和錯誤。今天我會用輕鬆的方式帶你們看看這些錯誤,讓你們能夠順利避開它們!

Youtube影片來源

1. 忘記配置 next.config.js

這是很多新手最常犯的錯誤之一。Next.js 的配置檔案 next.config.js 是非常重要的,它可以設定很多關鍵的選項。如果你忘記配置這個檔案,可能會遇到一些預期之外的行為。

解決方法

確保你有正確地配置 next.config.js,例如:

// next.config.js
module.exports = {
  reactStrictMode: true,
  images: {
    domains: ['example.com'],
  },
};

2. 使用客製化路由但忘記更新連結

有時候我們會需要客製化路由,但如果你忘記更新應用中的連結,使用者就會遇到 404 錯誤。

解決方法

確保你在更新路由後,也同步更新所有相關的連結。

// pages/product/[id].js
import { useRouter } from 'next/router';

const ProductPage = () => {
  const router = useRouter();
  const { id } = router.query;
  
  return <div>Product ID: {id}</div>;
};

export default ProductPage;

3. 忘記安裝必要的依賴

Next.js 使用很多外部套件,如果你忘記安裝這些依賴,應用程式就無法正常運作。

解決方法

記得在專案中執行以下命令安裝必要的套件:

npm install next react react-dom

4. 沒有正確配置靜態資源

Next.js 允許你使用 /public 資料夾來存放靜態資源,但如果你沒有正確配置,這些資源就無法被正確載入。

解決方法

確保你的靜態資源放在 /public 資料夾,並以正確的方式引用它們。

<img src="/images/logo.png" alt="Logo" />

5. 忽略錯誤處理

開發過程中難免會遇到錯誤,如果你忽略這些錯誤或沒有適當處理,會對使用者體驗造成很大的影響。

解決方法

使用 Next.js 提供的錯誤處理機制,例如 getInitialProps 中的錯誤處理。

// pages/_error.js
function Error({ statusCode }) {
  return (
    <p>
      {statusCode
        ? `An error ${statusCode} occurred on server`
        : 'An error occurred on client'}
    </p>
  );
}

Error.getInitialProps = ({ res, err }) => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
  return { statusCode };
};

export default Error;

6. 沒有優化效能

即使 Next.js 已經非常快,但還是有一些效能優化的工作需要我們去做。例如,沒有使用 lazy loading 來延遲載入非必要的資源。

解決方法

使用 Next.js 的 next/dynamic 來實現動態載入。

import dynamic from 'next/dynamic';

const DynamicComponent = dynamic(() => import('../components/DynamicComponent'), {
  ssr: false,
});

const Home = () => (
  <div>
    <DynamicComponent />
  </div>
);

export default Home;

7. 沒有適當處理 SEO

SEO(搜尋引擎最佳化)對於每個網站都非常重要,但很多新手會忽略這一點。

解決方法

使用 Next.js 的 next/head 組件來設定適當的 meta 標籤。

import Head from 'next/head';

const Home = () => (
  <div>
    <Head>
      <title>My Next.js App</title>
      <meta name="description" content="This is a Next.js app" />
    </Head>
    <h1>Welcome to my Next.js app!</h1>
  </div>
);

export default Home;

8. 沒有利用靜態生成

Next.js 提供了靜態生成(Static Generation)和伺服器端渲染(Server-Side Rendering)兩種模式,但很多新手只使用伺服器端渲染,忽略了靜態生成的優點。

解決方法

在適當的情況下使用 getStaticPropsgetStaticPaths 來實現靜態生成。

// pages/posts/[id].js
export async function getStaticPaths() {
  // Return a list of possible value for id
  const paths = [
    { params: { id: '1' } },
    { params: { id: '2' } },
  ];
  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  // Fetch necessary data for the blog post using params.id
  return {
    props: {
      post: { id: params.id, title: `Post ${params.id}` },
    },
  };
}

const Post = ({ post }) => {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>This is the blog post content.</p>
    </div>
  );
};

export default Post;

9. 未善用 next/image 組件

Next.js 提供的 next/image 組件可以幫助你優化圖片的加載,但很多新手仍然使用普通的 HTML <img> 標籤。

解決方法

使用 next/image 組件來替代 <img> 標籤,享受自動優化的好處。

import Image from 'next/image';

const Home = () => (
  <div>
    <Image src="/images/logo.png" alt="Logo" width={500} height={500} />
  </div>
);

export default Home;

10. 忽略環境變數設定

環境變數在應用程式開發中非常重要,但很多新手不知道如何在 Next.js 中正確使用它們。

解決方法

在根目錄下創建 .env.local 文件,並將環境變數存放在其中。

NEXT_PUBLIC_API_URL=https://api.example.com

然後在程式碼中使用它們:

const apiUrl = process.env.NEXT_PUBLIC_API_URL;

11. 沒有配置 ESLint 和 Prettier

代碼風格和品質對於一個項目來說非常重要,但很多新手會忽略配置 ESLint 和 Prettier。

解決方法

安裝並配置 ESLint 和 Prettier:

npm install eslint prettier eslint-plugin-prettier eslint-config-prettier --save-dev

創建 .eslintrc.json 文件:

{
  "extends": ["next", "prettier"]
}

創建 .prettierrc 文件:

{
  "singleQuote": true,
  "semi": false
}

12. 忘記使用 useEffect 處理副作用

在 React 中,useEffect 是用來處理副作用的,但很多新手會忘記使用它,導致無法正確處理數據加載等操作。

解決方法

在需要處理副作用的地方使用 useEffect

import { useEffect, useState } from 'react';

const Home = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('/api/data')
      .then((res) => res.json())
      .then((data) => setData(data));
  }, []);

  return <div>{data ? <p>{data.message}</p> : <p>Loading...</p>}</

div>;
};

export default Home;

13. 沒有使用 getServerSideProps 獲取伺服器端數據

當你需要在伺服器端獲取數據時,getServerSideProps 是非常有用的,但很多新手會忽略它的使用。

解決方法

在需要伺服器端數據的頁面使用 getServerSideProps

export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();

  return {
    props: { data },
  };
}

const Home = ({ data }) => {
  return <div>{data.message}</div>;
};

export default Home;

14. 沒有設定自定義 404 頁面

當用戶訪問不存在的頁面時,顯示一個友好的 404 頁面是非常重要的。

解決方法

pages 目錄下創建 404.js 文件:

const Custom404 = () => {
  return <h1>404 - Page Not Found</h1>;
};

export default Custom404;

Next.js 提供的 next/link 可以優化路由導航,但很多新手仍然使用傳統的 <a> 標籤。

解決方法

使用 next/link 來替代 <a> 標籤:

import Link from 'next/link';

const Home = () => (
  <div>
    <Link href="/about">
      <a>About</a>
    </Link>
  </div>
);

export default Home;

16. 忽略頁面的 getInitialProps

在某些情況下,你需要在伺服器端和客戶端獲取數據,此時 getInitialProps 就非常有用了。

解決方法

在頁面組件中使用 getInitialProps

const Page = ({ data }) => {
  return <div>{data.message}</div>;
};

Page.getInitialProps = async () => {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();
  return { data };
};

export default Page;

17. 沒有處理 API 路由的錯誤

在開發 API 路由時,忽略錯誤處理會導致難以排除問題。

解決方法

在 API 路由中添加錯誤處理:

export default async (req, res) => {
  try {
    const data = await fetch('https://api.example.com/data').then((res) =>
      res.json()
    );
    res.status(200).json(data);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch data' });
  }
};

18. 忽略 getStaticProps 的 ISR 功能

增量靜態再生(ISR)可以讓靜態頁面在背景中自動更新,但很多新手會忽略這個功能。

解決方法

getStaticProps 中使用 revalidate 屬性:

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();

  return {
    props: { data },
    revalidate: 10, // 每 10 秒重新生成一次
  };
}

const Home = ({ data }) => {
  return <div>{data.message}</div>;
};

export default Home;

19. 忽略 useRouter 處理路由事件

useRouter 可以讓你在組件中訪問路由對象,但很多新手會忽略它的使用。

解決方法

在需要訪問路由資訊的組件中使用 useRouter

import { useRouter } from 'next/router';

const Home = () => {
  const router = useRouter();

  return <div>Current route: {router.pathname}</div>;
};

export default Home;

20. 忽略 next/script 設定第三方腳本

Next.js 提供的 next/script 可以幫助你更好地管理第三方腳本,但很多新手會忽略它的使用。

解決方法

使用 next/script 來管理第三方腳本:

import Script from 'next/script';

const Home = () => (
  <div>
    <Script
      src="https://www.googletagmanager.com/gtag/js?id=GA_TRACKING_ID"
      strategy="afterInteractive"
    />
    <Script id="google-analytics" strategy="afterInteractive">
      {`
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'GA_TRACKING_ID');
      `}
    </Script>
    <h1>Welcome to my Next.js app!</h1>
  </div>
);

export default Home;

21. 忽略 next/head 設定頁面標題

每個頁面應該有不同的標題和 meta 標籤,但很多新手會忽略這一點。

解決方法

在每個頁面組件中使用 next/head 設定頁面標題和 meta 標籤:

import Head from 'next/head';

const Home = () => (
  <div>
    <Head>
      <title>Home Page</title>
      <meta name="description" content="This is the home page" />
    </Head>
    <h1>Welcome to the Home Page!</h1>
  </div>
);

export default Home;

22. 忽略 getStaticPaths 設定動態路由

在動態路由中使用 getStaticPaths 可以生成靜態頁面,但很多新手會忽略這一點。

解決方法

在動態路由頁面中使用 getStaticPaths

export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  const paths = posts.map((post) => ({
    params: { id: post.id.toString() },
  }));

  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  const res = await fetch(`https://api.example.com/posts/${params.id}`);
  const post = await res.json();

  return { props: { post } };
}

const Post = ({ post }) => {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
};

export default Post;

23. 忽略使用 SWR 進行數據獲取

SWR 是一個用於數據請求的 React Hook 庫,能夠自動處理數據快取和重新驗證。但很多新手會忽略它的使用。

解決方法

使用 SWR 進行數據獲取:

import useSWR from 'swr';

const fetcher = (url) => fetch(url).then((res) => res.json());

const Home = () => {
  const { data, error } = useSWR('/api/data', fetcher);

  if (error) return <div>Failed to load</div>;
  if (!data) return <div>Loading...</div>;

  return <div>{data.message}</div>;
};

export default Home;

24. 忽略 next/font 設定自定義字體

Next.js 提供的 next/font 可以幫助你更好地管理自定義字體,但很多新手會忽略它的使用。

解決方法

使用 next/font 來管理自定義字體:

import { createGlobalStyle } from 'styled-components';
import { OpenSans } from 'next/font/google';

const openSans = OpenSans({
  weight: '400',
  subsets: ['latin'],
});

const GlobalStyle = createGlobalStyle`
  body {
    font-family: '${openSans.style.fontFamily}', sans-serif;
  }
`;

const Home = () => (
  <div>
    <GlobalStyle />
    <h1>Welcome to my Next.js app!</h1>
  </div>
);

export default Home;

25. 忽略使用 Image Optimization

Next.js 提供的 Image Optimization 可以自動優化圖片,但很多新手會忽略這一點。

解決方法

使用 next/image 來自動優化圖片:

import Image from 'next/image';

const Home = () => (
  <div>
    <Image src="/images/logo.png" alt="Logo" width={500} height={500} />
  </div>
);

export default Home;

26. 忽略 next/router 處理導航事件

next/router 可以幫助你處理

導航事件,但很多新手會忽略它的使用。

解決方法

在需要處理導航事件的地方使用 next/router

import { useRouter } from 'next/router';

const Home = () => {
  const router = useRouter();

  const handleClick = () => {
    router.push('/about');
  };

  return <button onClick={handleClick}>Go to About Page</button>;
};

export default Home;

27. 忽略 Static File Serving

Next.js 允許你在 public 目錄下放置靜態文件,但很多新手會忽略這一點。

解決方法

將靜態文件放在 public 目錄下,並以 /public 作為根路徑引用它們:

<img src="/images/logo.png" alt="Logo" />

28. 忽略 Middleware

Next.js 提供的 Middleware 可以讓你在請求處理過程中插入自定義邏輯,但很多新手會忽略它的使用。

解決方法

pages/_middleware.js 文件中添加自定義邏輯:

export default function middleware(req, ev) {
  const { pathname } = req.nextUrl;
  if (pathname === '/') {
    return new Response('Hello, world!');
  }
}

29. 忽略 API Route 錯誤處理

在開發 API 路由時,忽略錯誤處理會導致難以排除問題。

解決方法

在 API 路由中添加錯誤處理:

export default async (req, res) => {
  try {
    const data = await fetch('https://api.example.com/data').then((res) =>
      res.json()
    );
    res.status(200).json(data);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch data' });
  }
};

希望這些常見錯誤和解決方法能幫助你更順利地使用 Next.js!如果你有任何問題或想分享你的經驗,歡迎在下方留言喔!