مقدمه
Next.js یکی از محبوبترین فریمورکهای React است که توسعه وبسایتهای مدرن را سریعتر و بهینهتر میکند. در نسخه 15 این فریمورک، قابلیتهای جدیدی معرفی شده که کار توسعهدهندگان را آسانتر میکند. یکی از مهمترین ویژگیهای Next.js، امکان ایجاد و استفاده از کامپوننتهای ساده برای ساختاردهی بهتر پروژه است. در این مقاله، نحوه ایجاد و مدیریت کامپوننتهای ساده در Next.js 15 را بررسی خواهیم کرد.
آشنایی با Next.js 15 و قابلیتهای آن
Next.js 15 تغییرات و بهینهسازیهای مختلفی را در مقایسه با نسخههای قبلی ارائه کرده است:
-
بهبود در Server Components برای افزایش عملکرد
-
پشتیبانی بهتر از React 18 و ویژگیهای جدید آن
-
بهینهسازیهای بیشتر برای SSR و SSG
-
امکان استفاده بهتر از API Route ها
مفاهیم پایهای کامپوننتها در React و Next.js
در React و Next.js، دو نوع کامپوننت وجود دارد:
-
کامپوننتهای تابعی (Function Components)
-
کامپوننتهای کلاسی (Class Components)
امروزه کامپوننتهای تابعی بیشتر مورد استفاده قرار میگیرند، زیرا سبکتر و خواناتر هستند و میتوانند از هوکها (Hooks) برای مدیریت وضعیت (State) استفاده کنند.
راهاندازی پروژه Next.js 15
برای شروع، ابتدا باید یک پروژه Next.js جدید راهاندازی کنیم. میتوانیم این کار را با دستور زیر انجام دهیم:
npx create-next-app@latest my-next-app
cd my-next-app
npm run dev
این دستورات، پروژه را اجرا کرده و سرور محلی را در آدرس http://localhost:3000 راهاندازی میکند.
ایجاد اولین کامپوننت ساده در Next.js
یک کامپوننت ساده در Next.js به صورت زیر تعریف میشود:
const Greeting = () => {
return <h1>سلام، به دنیای Next.js خوش آمدید!</h1>;
};
export default Greeting;
برای استفاده از این کامپوننت، کافی است آن را در صفحه index.js وارد کنیم:
import Greeting from "../components/Greeting";
export default function Home() {
return (
<div>
<Greeting />
</div>
);
}
ارسال props به کامپوننتها
props به ما امکان میدهد که دادهها را به کامپوننتها ارسال کنیم:
و در صفحه اصلی:
const Greeting = ({ name }) => {
return <h1>سلام {name}، به دنیای Next.js خوش آمدید!</h1>;
};
export default Greeting;
استایلدهی به کامپوننتها
استفاده از CSS Modules
/* greeting.module.css */
.title {
color: blue;
font-size: 24px;
}
import styles from "./greeting.module.css";
const Greeting = () => {
return <h1 className={styles.title}>سلام، به Next.js خوش آمدید!</h1>;
};
استفاده از Tailwind CSS
npm install tailwindcss
const Greeting = () => {
return <h1 className="text-blue-500 text-xl">سلام، به Next.js خوش آمدید!</h1>;
};
مدیریت state در کامپوننتها
برای مدیریت state از هوک useState استفاده میکنیم:
import { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>تعداد: {count}</p>
<button onClick={() => setCount(count + 1)}>افزایش</button>
</div>
);
};
export default Counter;
مدیریت State (وضعیت) در کامپوننتهای Next.js 15 یکی از چالشهای مهم در توسعه اپلیکیشنهای تحت وب است. State در React و Next.js به شما امکان میدهد دادهها را درون یک کامپوننت ذخیره کرده و در صورت نیاز بهروزرسانی کنید. این فرآیند باعث تعاملپذیری و پویایی اپلیکیشن میشود.
در Next.js، کامپوننتها میتوانند به دو دسته کلی تقسیم شوند:
- Server Components → این کامپوننتها در سرور اجرا شده و نمیتوانند
stateداشته باشند. - Client Components → این کامپوننتها در مرورگر اجرا شده و میتوانند از
stateوhooksاستفاده کنند.
1. مدیریت State در کامپوننتهای کلاینتی (Client Components)
برای استفاده از State در یک کامپوننت، باید از هوک useState استفاده کنیم. همچنین، باید تعیین کنیم که کامپوننت در کلاینت اجرا شود، که این کار با اضافه کردن ”use client” در ابتدای فایل امکانپذیر است.
مثال: مدیریت یک شمارنده ساده
"use client";
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>مقدار شمارنده: {count}</p>
<button onClick={() => setCount(count + 1)}>افزایش</button>
<button onClick={() => setCount(count - 1)}>کاهش</button>
</div>
);
}
export default Counter;
🔹 در این مثال:
- مقدار اولیه
countبرابر با0است. - با کلیک روی دکمه "افزایش"، مقدار
countیک واحد افزایش مییابد. - با کلیک روی دکمه "کاهش"، مقدار
countیک واحد کاهش مییابد.
این روش مناسب مدیریت وضعیتهای محلی و کوتاهمدت در کامپوننتهای کلاینتی است.
2. مدیریت State بین چندین کامپوننت (State Lifting)
اگر چندین کامپوننت به یک وضعیت مشترک (State) نیاز داشته باشند، باید این State را در کامپوننت والد (Parent Component) نگهداری کرده و آن را به فرزندان ارسال کنیم. این تکنیک به State Lifting معروف است.
مثال: اشتراکگذاری State بین دو کامپوننت
"use client";
import { useState } from "react";
function ParentComponent() {
const [message, setMessage] = useState("سلام!");
return (
<div>
<ChildComponent message={message} />
<button onClick={() => setMessage("Next.js عالی است!")}>
تغییر پیام
</button>
</div>
);
}
function ChildComponent({ message }) {
return <p>پیام دریافت شده: {message}</p>;
}
export default ParentComponent;
🔹 در این مثال:
- State
messageدر کامپوننت والد قرار دارد و مقدار اولیه آن"سلام!"است. - کامپوننت فرزند (ChildComponent) مقدار
messageرا از والد دریافت میکند. - با کلیک روی دکمه، مقدار
messageتغییر کرده و این تغییر در کامپوننت فرزند نیز اعمال میشود.
این روش برای مدیریت State در سطوح مختلف اپلیکیشن مناسب است.
3. مدیریت State در سطح گسترده با Context API
اگر نیاز باشد State بین چندین کامپوننت که ارتباط مستقیمی ندارند به اشتراک گذاشته شود، Context API گزینه مناسبی است. این روش به شما کمک میکند تا از پراپدرلینگ (Prop Drilling) که باعث پیچیدگی کد میشود، جلوگیری کنید.
مثال: مدیریت حالت تم (روشن/تاریک) با Context API
گام 1: ایجاد یک Context برای مدیریت تم
"use client";
import { createContext, useState, useContext } from "react";
// ایجاد Context
const ThemeContext = createContext();
// کامپوننت Provider که تم را مدیریت میکند
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// هوک اختصاصی برای استفاده از Context
export function useTheme() {
return useContext(ThemeContext);
}
گام 2: استفاده از ThemeProvider در برنامه
import { ThemeProvider } from "./ThemeContext";
import ThemeSwitcher from "./ThemeSwitcher";
function App() {
return (
<ThemeProvider>
<ThemeSwitcher />
</ThemeProvider>
);
}
export default App;
گام 3: ایجاد کامپوننتی که از Context استفاده میکند
import { useTheme } from "./ThemeContext";
function ThemeSwitcher() {
const { theme, toggleTheme } = useTheme();
return (
<div className={theme === "light" ? "bg-white text-black" : "bg-black text-white"}>
<p>تم فعلی: {theme}</p>
<button onClick={toggleTheme}>تغییر تم</button>
</div>
);
}
export default ThemeSwitcher;
در این روش:
ThemeContextوضعیت تم را مدیریت میکند و مقدارthemeوtoggleThemeرا در اختیار کامپوننتها قرار میدهد.- با استفاده از
useContext، کامپوننتها به مقدارthemeدسترسی دارند و میتوانند آن را تغییر دهند. - این روش برای مدیریت حالتهایی که در بخشهای مختلف برنامه استفاده میشوند (مانند احراز هویت، زبان، تم و ...) بسیار مناسب است.
استفاده از useEffect در کامپوننتها
برای اجرای عملیات پس از رندر شدن کامپوننت، از useEffect استفاده میشود:
import { useState, useEffect } from "react";
const Timer = () => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <p>زمان سپری شده: {seconds} ثانیه</p>;
};
export default Timer;