مقدمه

تاکنون با اصول اولیه کار با state آشنا شده‌ایم. در این درس، به بررسی چند الگوی رایج و بهترین شیوه‌ها برای کار با stateهای پیچیده‌تر، به خصوص اشیاء و آرایه‌ها، می‌پردازیم. رعایت این الگوها به شما کمک می‌کند تا از باگ‌های رایج جلوگیری کرده و کدهای قابل پیش‌بینی و قابل نگهداری بنویسید.

اصل تغییرناپذیری (Immutability)

مهم‌ترین قانونی که باید هنگام کار با state در React به خاطر بسپارید، اصل «تغییرناپذیری» است. شما هرگز نباید یک متغیر state را مستقیماً تغییر دهید (mutate کنید). به جای آن، همیشه باید با استفاده از تابع setter یک مقدار جدید را جایگزین مقدار قبلی کنید.

به‌روزرسانی اشیاء در state

اگر state شما یک شیء است، برای به‌روزرسانی آن باید یک شیء جدید بسازید. برای این کار، معمولاً از سینتکس spread (...) در جاوااسکریپت برای کپی کردن مقادیر قبلی و بازنویسی مقادیر جدید استفاده می‌شود.

Copy Icon JAVASCRIPT (React)
import { useState } from 'react';

function UserProfile() {
  const [user, setUser] = useState({ name: 'Alice', age: 30 });

  function handleAgeIncrease() {
    // Create a new object with the updated age
    setUser({ ...user, age: user.age + 1 });
  }

  // ... return JSX
}

در این کد، ما به جای user.age++ (که یک mutation مستقیم است)، یک شیء کاملاً جدید می‌سازیم، تمام مقادیر قبلی user را در آن کپی می‌کنیم (...user) و سپس مقدار age را بازنویسی می‌کنیم.

به‌روزرسانی آرایه‌ها در state

همین اصل برای آرایه‌ها نیز صادق است. برای افزودن، حذف یا ویرایش آیتم‌ها در یک آرایه state، باید یک آرایه جدید بسازید.

افزودن به یک آرایه

برای افزودن آیتم جدید به آرایه state کافی است یک آرایه جدید بسازید که شامل همه آیتم‌های قبلی و آیتم جدید باشد. معمولاً از سینتکس spread استفاده می‌شود:

Copy Icon JAVASCRIPT (React)
const [todos, setTodos] = useState([ { id: 1, text: 'Learn React' } ]);

function addTodo() {
    const newTodo = { id: 2, text: 'Build a project' };
    setTodos([...todos, newTodo]); // Create a new array
}

حذف از یک آرایه

برای حذف یک آیتم از آرایه state، باید یک آرایه جدید بسازید که آیتم مورد نظر را حذف کرده باشد. متد filter برای این کار بسیار مناسب است؛ زیرا همیشه یک آرایه جدید برمی‌گرداند و آرایه اصلی را تغییر نمی‌دهد.

Copy Icon JAVASCRIPT (React)
function deleteTodo(todoId) {
    setTodos(todos.filter(t => t.id !== todoId)); // `filter` returns a new array
}

ویرایش یک آیتم در آرایه

برای ویرایش یک آیتم در آرایه state باید یک آرایه جدید بسازید که آیتم مورد نظر را با مقدار جدید جایگزین کند. متد map برای این کار مناسب است؛ زیرا هر آیتم را بررسی کرده و فقط آیتم مورد نظر را تغییر می‌دهد.

Copy Icon JAVASCRIPT (React)
function updateTodo(todoId, newText) {
    setTodos(todos.map(t => {
      if (t.id === todoId) {
        return { ...t, text: newText }; // Create a new object for the updated item
      } else {
        return t;
      }
    })); // `map` returns a new array
}

در تمام این مثال‌ها، ما از متدهای آرایه مانند map و filter که آرایه‌های جدیدی را برمی‌گردانند، استفاده می‌کنیم و از متدهایی مانند push یا splice که آرایه اصلی را مستقیماً تغییر می‌دهند، پرهیز می‌کنیم.

استفاده از تابع به‌روزرسان (Updater Function)

در درس قبل دیدیم که state در هر رندر یک عکس فوری است. اگر نیاز به به‌روزرسانی state بر اساس مقدار قبلی آن دارید، به خصوص اگر این به‌روزرسانی ممکن است چندین بار پشت سر هم اتفاق بیفتد، روش امن‌تر استفاده از یک «تابع به‌روزرسان» است.

Copy Icon JAVASCRIPT (React)
function handleClick() {
    // Pass a function to the setter to update based on the previous state
    setCount(c => c + 1);
    setCount(c => c + 1);
    setCount(c => c + 1);
    // This will correctly increment the counter by 3
  }

وقتی شما یک تابع را به setter پاس می‌دهید، React آن را در صف قرار داده و تضمین می‌کند که این تابع مقدار state به‌روز شده از پردازش قبلی را به عنوان آرگومان دریافت خواهد کرد.

در این درس، با الگوهای کلیدی برای مدیریت stateهای پیچیده‌تر در React آشنا شدیم. اصل تغییرناپذیری و استفاده از توابع به‌روزرسان، سنگ بنای نوشتن کدهای React قابل پیش‌بینی و بدون باگ هستند. با این درس، فصل «تعاملی‌کردن ری‌اکت با state» به پایان می‌رسد. شما اکنون می‌توانید کامپوننت‌های کاملاً پویا و تعاملی بسازید. در فصل بعدی، به «افکت‌ها و چرخه حیات کامپوننت» خواهیم پرداخت و با هوک قدرتمند useEffect آشنا خواهیم شد.