哥记 發表於 2024-12-25 17:18:00

Next.js 14 基础入门:从项目搭建到核心概念

<p>Next.js 14 带来了许多激动人心的新特性,包括局部渲染、Server Actions 增强等。作为一名前端开发者,我最近在项目中升级到了 Next.js 14,今天就来分享一下从项目搭建到实际应用的完整过程。</p>
<h2 id="项目初始化">项目初始化</h2>
<p>首先,让我们创建一个全新的 Next.js 14 项目:</p>
<pre><code class="language-bash"># 使用 create-next-app 创建项目
npx create-next-app@latest my-next-app
</code></pre>
<p>在初始化过程中,你会看到以下选项:</p>
<pre><code class="language-bash">✔ Would you like to use TypeScript? Yes
✔ Would you like to use ESLint? Yes
✔ Would you like to use Tailwind CSS? Yes
✔ Would you like to use `src/` directory? Yes
✔ Would you like to use App Router? Yes
✔ Would you like to customize the default import alias? No
</code></pre>
<h2 id="目录结构解析">目录结构解析</h2>
<p>创建完成后,我们来看看项目的核心目录结构:</p>
<pre><code>my-next-app/
├── src/
│   ├── app/
│   │   ├── layout.tsx      # 根布局文件
│   │   ├── page.tsx      # 首页组件
│   │   ├── error.tsx       # 错误处理组件
│      ├── loading.tsx   # 加载状态组件
│   │   └── not-found.tsx   # 404页面组件
│   ├── components/         # 组件目录
│   └── lib/               # 工具函数目录
├── public/                # 静态资源目录
├── next.config.js      # Next.js 配置文件
└── package.json          # 项目依赖配置
</code></pre>
<h2 id="app-router-基础">App Router 基础</h2>
<p>Next.js 14 推荐使用 App Router,它基于 React Server Components,提供了更好的性能和开发体验。</p>
<h3 id="1-基础路由">1. 基础路由</h3>
<pre><code class="language-typescript">// src/app/page.tsx - 首页
export default function Home() {
return (
    &lt;main className="flex min-h-screen flex-col items-center justify-between p-24"&gt;
      &lt;h1&gt;Welcome to Next.js 14&lt;/h1&gt;
    &lt;/main&gt;
);
}

// src/app/about/page.tsx - 关于页面
export default function About() {
return (
    &lt;div className="p-24"&gt;
      &lt;h1&gt;About Us&lt;/h1&gt;
    &lt;/div&gt;
);
}
</code></pre>
<h3 id="2-布局组件">2. 布局组件</h3>
<pre><code class="language-typescript">// src/app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
    &lt;html lang="en"&gt;
      &lt;body&gt;
      &lt;header&gt;
          &lt;nav&gt;{/* 导航栏组件 */}&lt;/nav&gt;
      &lt;/header&gt;
      &lt;main&gt;{children}&lt;/main&gt;
      &lt;footer&gt;{/* 页脚组件 */}&lt;/footer&gt;
      &lt;/body&gt;
    &lt;/html&gt;
);
}

// src/app/blog/layout.tsx - 博客专属布局
export default function BlogLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
    &lt;div className="blog-layout"&gt;
      &lt;aside className="blog-sidebar"&gt;
      {/* 博客侧边栏 */}
      &lt;/aside&gt;
      &lt;div className="blog-content"&gt;
      {children}
      &lt;/div&gt;
    &lt;/div&gt;
);
}
</code></pre>
<h2 id="数据获取">数据获取</h2>
<p>Next.js 14 提供了多种数据获取方式,默认都是基于 Server Components:</p>
<h3 id="1-服务端获取数据">1. 服务端获取数据</h3>
<pre><code class="language-typescript">// src/app/posts/page.tsx
async function getPosts() {
const res = await fetch('https://api.example.com/posts', {
    next: {
      revalidate: 3600 // 1小时重新验证一次
    }
});

if (!res.ok) {
    throw new Error('Failed to fetch posts');
}

return res.json();
}

export default async function Posts() {
const posts = await getPosts();

return (
    &lt;div className="posts-grid"&gt;
      {posts.map(post =&gt; (
      &lt;PostCard key={post.id} post={post} /&gt;
      ))}
    &lt;/div&gt;
);
}
</code></pre>
<h3 id="2-动态路由数据获取">2. 动态路由数据获取</h3>
<pre><code class="language-typescript">// src/app/posts//page.tsx
async function getPost(id: string) {
const res = await fetch(`https://api.example.com/posts/${id}`, {
    cache: 'no-store' // 禁用缓存,始终获取最新数据
});

if (!res.ok) {
    throw new Error('Failed to fetch post');
}

return res.json();
}

export default async function Post({
params: { id }
}: {
params: { id: string }
}) {
const post = await getPost(id);

return (
    &lt;article className="post-detail"&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;div&gt;{post.content}&lt;/div&gt;
    &lt;/article&gt;
);
}
</code></pre>
<h2 id="server-actions">Server Actions</h2>
<p>Next.js 14 增强了 Server Actions,让表单处理变得更简单:</p>
<pre><code class="language-typescript">// src/app/posts/new/page.tsx
export default function NewPost() {
async function createPost(formData: FormData) {
    'use server';
   
    const title = formData.get('title');
    const content = formData.get('content');
   
    // 服务端验证
    if (!title || !content) {
      throw new Error('Title and content are required');
    }
   
    // 直接在服务端处理数据
    await db.post.create({
      data: {
      title: title as string,
      content: content as string,
      },
    });
   
    // 重定向到文章列表
    redirect('/posts');
}

return (
    &lt;form action={createPost}&gt;
      &lt;input type="text" name="title" placeholder="文章标题" /&gt;
      &lt;textarea name="content" placeholder="文章内容" /&gt;
      &lt;button type="submit"&gt;发布文章&lt;/button&gt;
    &lt;/form&gt;
);
}
</code></pre>
<h2 id="客户端组件">客户端组件</h2>
<p>虽然 Server Components 是默认的,但有时我们需要客户端交互:</p>
<pre><code class="language-typescript">// src/components/Counter.tsx
'use client';

import { useState } from 'react';

export default function Counter() {
const = useState(0);

return (
    &lt;div&gt;
      &lt;p&gt;Count: {count}&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
      Increment
      &lt;/button&gt;
    &lt;/div&gt;
);
}
</code></pre>
<h2 id="元数据配置">元数据配置</h2>
<p>Next.js 14 提供了强大的元数据 API:</p>
<pre><code class="language-typescript">// src/app/layout.tsx
import { Metadata } from 'next';

export const metadata: Metadata = {
title: {
    template: '%s | My Next.js App',
    default: 'My Next.js App',
},
description: 'Built with Next.js 14',
openGraph: {
    title: 'My Next.js App',
    description: 'Built with Next.js 14',
    images: ['/og-image.jpg'],
},
};

// src/app/blog//page.tsx
export async function generateMetadata({
params
}: {
params: { slug: string }
}): Promise&lt;Metadata&gt; {
const post = await getPost(params.slug);

return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: ,
    },
};
}
</code></pre>
<h2 id="静态资源处理">静态资源处理</h2>
<p>Next.js 14 优化了图片和字体的处理:</p>
<pre><code class="language-typescript">// src/components/ProfileImage.tsx
import Image from 'next/image';

export default function ProfileImage() {
return (
    &lt;Image
      src="/profile.jpg"
      alt="Profile"
      width={200}
      height={200}
      placeholder="blur"
      blurDataURL="data:image/jpeg;base64,..."
      priority
    /&gt;
);
}

// src/app/layout.tsx
import { Inter } from 'next/font/google';

const inter = Inter({
subsets: ['latin'],
display: 'swap',
});

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
    &lt;html lang="en" className={inter.className}&gt;
      &lt;body&gt;{children}&lt;/body&gt;
    &lt;/html&gt;
);
}
</code></pre>
<h2 id="环境配置">环境配置</h2>
<p>Next.js 14 支持多环境配置:</p>
<pre><code class="language-env"># .env.local
DATABASE_URL="postgresql://..."
API_KEY="your-api-key"

# .env.production
NEXT_PUBLIC_API_URL="https://api.production.com"

# .env.development
NEXT_PUBLIC_API_URL="http://localhost:3000"
</code></pre>
<p>使用环境变量:</p>
<pre><code class="language-typescript">// src/lib/db.ts
const dbUrl = process.env.DATABASE_URL;
const apiKey = process.env.API_KEY;

// 客户端也可以使用 NEXT_PUBLIC_ 前缀的环境变量
console.log(process.env.NEXT_PUBLIC_API_URL);
</code></pre>
<h2 id="错误处理">错误处理</h2>
<p>Next.js 14 提供了完善的错误处理机制:</p>
<pre><code class="language-typescript">// src/app/error.tsx
'use client';

export default function Error({
error,
reset,
}: {
error: Error;
reset: () =&gt; void;
}) {
return (
    &lt;div className="error-container"&gt;
      &lt;h2&gt;Something went wrong!&lt;/h2&gt;
      &lt;p&gt;{error.message}&lt;/p&gt;
      &lt;button onClick={() =&gt; reset()}&gt;Try again&lt;/button&gt;
    &lt;/div&gt;
);
}

// src/app/not-found.tsx
export default function NotFound() {
return (
    &lt;div className="not-found"&gt;
      &lt;h2&gt;404 - Page Not Found&lt;/h2&gt;
      &lt;p&gt;Could not find requested resource&lt;/p&gt;
    &lt;/div&gt;
);
}
</code></pre>
<h2 id="开发调试">开发调试</h2>
<p>Next.js 14 改进了开发体验:</p>
<pre><code class="language-typescript">// 使用 React Developer Tools
import { useDebugValue } from 'react';

function useCustomHook() {
const value = // ... 一些计算

// 在 React DevTools 中显示自定义值
useDebugValue(value, value =&gt; `Custom: ${value}`);

return value;
}

// 使用 next.config.js 配置开发环境
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
// 启用详细的构建输出
logging: {
    fetches: {
      fullUrl: true,
    },
},
// 配置重写规则
rewrites: async () =&gt; {
    return [
      {
      source: '/api/:path*',
      destination: 'http://localhost:3001/api/:path*',
      },
    ];
},
};

module.exports = nextConfig;
</code></pre>
<h2 id="写在最后">写在最后</h2>
<p>Next.js 14 带来了许多激动人心的新特性,特别是在性能优化和开发体验方面有了显著提升。这篇文章介绍的只是基础功能,在实际项目中,你还可以:</p>
<ol>
<li>使用 Middleware 进行路由控制</li>
<li>配置国际化路由</li>
<li>实现增量静态再生成(ISR)</li>
<li>使用 Edge Runtime 优化性能</li>
<li>集成各种第三方服务</li>
</ol>
<p>在接下来的系列文章中,我们会深入探讨这些进阶主题。如果你对某个特定主题特别感兴趣,欢迎在评论区告诉我!</p>
<p>如果觉得这篇文章对你有帮助,别忘了点个赞 👍</p><br><br>
来源:https://www.cnblogs.com/yuanyanglu/p/18630998
頁: [1]
查看完整版本: Next.js 14 基础入门:从项目搭建到核心概念