فارسی

برای مدیریت وضعیت کارآمد در اپلیکیشن‌های خود، بر کانتکست ری‌اکت مسلط شوید. یاد بگیرید چه زمانی از کانتکست استفاده کنید، چگونه آن را به طور مؤثر پیاده‌سازی کنید و از اشتباهات رایج بپرهیزید.

کانتکست ری‌اکت: یک راهنمای جامع

کانتکست ری‌اکت (React Context) یک ویژگی قدرتمند است که به شما امکان می‌دهد داده‌ها را بین کامپوننت‌ها به اشتراک بگذارید بدون اینکه نیاز باشد به صراحت props را از طریق هر سطح از درخت کامپوننت عبور دهید. این ویژگی راهی برای در دسترس قرار دادن مقادیر خاص برای تمام کامپوننت‌ها در یک زیردرخت مشخص فراهم می‌کند. این راهنما به بررسی زمان و نحوه استفاده مؤثر از کانتکست ری‌اکت، به همراه بهترین شیوه‌ها و اشتباهات رایج برای اجتناب از آن‌ها می‌پردازد.

درک مشکل: Prop Drilling

در اپلیکیشن‌های پیچیده ری‌اکت، ممکن است با مشکل "prop drilling" (حفاری پراپ) مواجه شوید. این اتفاق زمانی رخ می‌دهد که شما نیاز دارید داده‌ها را از یک کامپوننت والد به یک کامپوننت فرزند که در عمق زیادی قرار دارد، منتقل کنید. برای انجام این کار، شما باید داده‌ها را از طریق هر کامپوننت واسط عبور دهید، حتی اگر آن کامپوننت‌ها خودشان به آن داده‌ها نیازی نداشته باشند. این می‌تواند منجر به موارد زیر شود:

این مثال ساده را در نظر بگیرید:


function App() {
  const user = { name: 'Alice', theme: 'dark' };
  return (
    <Layout user={user} />
  );
}

function Layout({ user }) {
  return (
    <Header user={user} />
  );
}

function Header({ user }) {
  return (
    <Navigation user={user} />
  );
}

function Navigation({ user }) {
  return (
    <Profile user={user} />
  );
}

function Profile({ user }) {
  return (
    <p>Welcome, {user.name}!
Theme: {user.theme}</p>
  );
}

در این مثال، شیء user از طریق چندین کامپوننت منتقل می‌شود، در حالی که فقط کامپوننت Profile واقعاً از آن استفاده می‌کند. این یک مورد کلاسیک از prop drilling است.

معرفی کانتکست ری‌اکت

کانتکست ری‌اکت راهی برای جلوگیری از prop drilling فراهم می‌کند، با این امکان که داده‌ها را بدون پاس دادن صریح از طریق props، در دسترس هر کامپوننتی در یک زیردرخت قرار دهد. این ویژگی شامل سه بخش اصلی است:

چه زمانی از کانتکست ری‌اکت استفاده کنیم

کانتکست ری‌اکت به ویژه برای به اشتراک‌گذاری داده‌هایی مفید است که برای درختی از کامپوننت‌های ری‌اکت "سراسری" (global) در نظر گرفته می‌شوند. این موارد می‌تواند شامل موارد زیر باشد:

ملاحظات مهم:

نحوه استفاده از کانتکست ری‌اکت: یک مثال عملی

بیایید به مثال prop drilling برگردیم و آن را با استفاده از کانتکست ری‌اکت حل کنیم.

۱. ایجاد یک کانتکست

ابتدا، یک کانتکست با استفاده از React.createContext() ایجاد کنید. این کانتکست داده‌های کاربر را نگهداری خواهد کرد.


// UserContext.js
import React from 'react';

const UserContext = React.createContext(null); // Default value can be null or an initial user object

export default UserContext;

۲. ایجاد یک Provider

سپس، ریشه اپلیکیشن خود (یا زیردرخت مربوطه) را با UserContext.Provider بپوشانید. شیء user را به عنوان پراپ value به Provider پاس دهید.


// App.js
import React from 'react';
import UserContext from './UserContext';
import Layout from './Layout';

function App() {
  const user = { name: 'Alice', theme: 'dark' };
  return (
    <UserContext.Provider value={user}>
      <Layout />
    </UserContext.Provider>
  );
}

export default App;

۳. مصرف کردن کانتکست

اکنون، کامپوننت Profile می‌تواند به داده‌های user مستقیماً از طریق کانتکست با استفاده از هوک useContext دسترسی پیدا کند. دیگر خبری از prop drilling نیست!


// Profile.js
import React, { useContext } from 'react';
import UserContext from './UserContext';

function Profile() {
  const user = useContext(UserContext);

  return (
    <p>Welcome, {user.name}!
Theme: {user.theme}</p>
  );
}

export default Profile;

کامپوننت‌های واسط (Layout، Header و Navigation) دیگر نیازی به دریافت پراپ user ندارند.


// Layout.js, Header.js, Navigation.js
import React from 'react';

function Layout({ children }) {
  return (
    <div>
      <Header />
      <main>{children}</main>
    </div>
  );
}

function Header() {
  return (<Navigation />);
}

function Navigation() {
  return (<Profile />);
}

export default Layout;

استفاده پیشرفته و بهترین شیوه‌ها

۱. ترکیب کانتکست با useReducer

برای مدیریت وضعیت پیچیده‌تر، می‌توانید کانتکست ری‌اکت را با هوک useReducer ترکیب کنید. این به شما امکان می‌دهد تا به‌روزرسانی‌های وضعیت را به روشی قابل پیش‌بینی‌تر و قابل نگهداری‌تر مدیریت کنید. کانتکست وضعیت را فراهم می‌کند و reducer انتقال‌های وضعیت را بر اساس actionهای ارسال شده مدیریت می‌کند.


// ThemeContext.js
import React, { createContext, useReducer } from 'react';

const ThemeContext = createContext();

const initialState = { theme: 'light' };

const themeReducer = (state, action) => {
  switch (action.type) {
    case 'TOGGLE_THEME':
      return { ...state, theme: state.theme === 'light' ? 'dark' : 'light' };
    default:
      return state;
  }
};

function ThemeProvider({ children }) {
  const [state, dispatch] = useReducer(themeReducer, initialState);

  return (
    <ThemeContext.Provider value={{ ...state, dispatch }}>
      {children}
    </ThemeContext.Provider>
  );
}

export { ThemeContext, ThemeProvider };



// ThemeToggle.js
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function ThemeToggle() {
  const { theme, dispatch } = useContext(ThemeContext);

  return (
    <button onClick={() => dispatch({ type: 'TOGGLE_THEME' })}>
      Toggle Theme (Current: {theme})
    </button>
  );
}

export default ThemeToggle;



// App.js
import React from 'react';
import { ThemeProvider } from './ThemeContext';
import ThemeToggle from './ThemeToggle';

function App() {
  return (
    <ThemeProvider>
      <div>
        <ThemeToggle />
      </div>
    </ThemeProvider>
  );
}

export default App;

۲. کانتکست‌های چندگانه

شما می‌توانید از چندین کانتکست در اپلیکیشن خود استفاده کنید اگر انواع مختلفی از داده‌های سراسری برای مدیریت دارید. این به جداسازی دغدغه‌ها و بهبود سازماندهی کد کمک می‌کند. به عنوان مثال، ممکن است یک UserContext برای احراز هویت کاربر و یک ThemeContext برای مدیریت تم اپلیکیشن داشته باشید.

۳. بهینه‌سازی عملکرد

همانطور که قبلاً ذکر شد، تغییرات کانتکست می‌تواند باعث رندرهای مجدد در کامپوننت‌های مصرف‌کننده شود. برای بهینه‌سازی عملکرد، موارد زیر را در نظر بگیرید:

۴. استفاده از هوک‌های سفارشی برای دسترسی به کانتکست

هوک‌های سفارشی ایجاد کنید تا منطق دسترسی و به‌روزرسانی مقادیر کانتکست را کپسوله کنید. این کار خوانایی و قابلیت نگهداری کد را بهبود می‌بخشد. برای مثال:


// useTheme.js
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
}

export default useTheme;



// MyComponent.js
import React from 'react';
import useTheme from './useTheme';

function MyComponent() {
  const { theme, dispatch } = useTheme();

  return (
    <div>
      Current Theme: {theme}
      <button onClick={() => dispatch({ type: 'TOGGLE_THEME' })}>
        Toggle Theme
      </button>
    </div>
  );
}

export default MyComponent;

اشتباهات رایج که باید از آنها اجتناب کرد

جایگزین‌های کانتکست ری‌اکت

در حالی که کانتکست ری‌اکت ابزار ارزشمندی است، همیشه بهترین راه‌حل نیست. این جایگزین‌ها را در نظر بگیرید:

نتیجه‌گیری

کانتکست ری‌اکت یک ویژگی قدرتمند برای به اشتراک‌گذاری داده‌ها بین کامپوننت‌ها بدون prop drilling است. درک زمان و نحوه استفاده مؤثر از آن برای ساخت اپلیکیشن‌های ری‌اکت قابل نگهداری و با عملکرد بالا بسیار مهم است. با پیروی از بهترین شیوه‌های ذکر شده در این راهنما و اجتناب از اشتباهات رایج، می‌توانید از کانتکست ری‌اکت برای بهبود کد خود و ایجاد تجربه کاربری بهتر بهره‌مند شوید. به یاد داشته باشید که نیازهای خاص خود را ارزیابی کرده و قبل از تصمیم‌گیری برای استفاده از کانتکست، جایگزین‌ها را نیز در نظر بگیرید.