تغییرات اخیر

در اینجا اطلاعیه‌ها، نسخه‌ها و تغییرات جدید لیارا فهرست می‌شوند.

۴ اشتباه رایج در هنگام استفاده از useState در ری اکت React


۳۰ فروردین ۱۴۰۴

ری‌ اکت (React) یکی از محبوب‌ترین ابزارهای توسعه وب است که به دلیل نحوه خاصی که در مدیریت وضعیت (state) داخل کامپوننت‌ها دارد، محبوبیت زیادی پیدا کرده و مورد استفاده قرار می‌گیرد. یکی از هوک‌های مهم در ری‌ اکت، useState است.

این هوک در ظاهر ساده به نظر می‌رسد، اما بسیاری از توسعه‌دهندگان، حتی کسانی که تجربه کافی دارند، ممکن است در موقع استفاده از آن دچار اشتباهاتی شوند. باید در نظر داشت که این اشتباهات می‌توانند باعث بروز مشکلاتی در عملکرد اپلیکیشن‌ها شوند.

در این مطلب از لیارا قصد داریم که به چهار اشتباه اصلی و رایج در استفاده از useState در ری اکت React بپردازیم و نحوه جلوگیری از آن‌ها را بررسی کنیم.

همین الان، هاست ابری React را با سرعت بالا راه‌اندازی کنید.
✅ بدون نیاز به پیکربندی ✅ استقرار آسان ✅ مناسب برای React
خرید هاست React

“برای ساخت برنامه React می‌توانید از مستندات لیارا استفاده کنید.”

آنچه در ادامه خواهید خواند:

  • خلاصه از از ری اکت
  • 4 اشتباه رایج در هنگام استفاده از useState در React
  • سوالات متداول
  • جمع بندی
useState در ری اکت React

خلاصه از از ری اکت

ری اکت یک کتابخانه متن باز جاوا اسکریپت است که اولین بار در سال 2013 توسط تیمی از توسعه‌دهندگان شرکت فیسبوک معرفی شد. این ابزار برای ساخت رابط‌های کاربری (UI) طراحی شده است و به برنامه‌نویسان فرانت کمک می‌کند که اجزای صفحات وب را سریع‌، ساختارمند و با قابلیت استفاده مجدد طراحی کنند.

در ری اکت، دو اصطلاح کتابخانه و فریم‌ورک اغلب به کار می‌رود. اگرچه ممکن است در ظاهر مشابه باشند، اما هر کدام از آن‌ها در مفهوم تفاوت‌هایی دارند.

کتابخانه‌ها معمولاً مجموعه‌ای کم‌حجم و منعطف از کدهای آماده هستند که وظایف خاصی را انجام می‌دهند و می‌توان مجدداً از آن‌ها استفاده کرد. در مقابل، فریم‌ورک‌ها ساختاری کامل و گسترده‌تر هستند که نحوه نوشتن و سازمان‌دهی کدها را تا حد زیادی مشخص می‌کنند.

ری اکت از این نظر ابزار منحصری است، زیرا می‌توان به‌صورت همزمان از برخی از ویژگی‌های کتابخانه و فریم‌ورک‌ها استفاده کرد. از سوی دیگر، بسیار راحت و منعطف است و تنها بر بخش رابط کاربری تمرکز دارد. همچنین قابلیت گسترش و استفاده در پروژه‌های سخت‌تر را فراهم می‌کند. به همین ترتیب، ری اکت به یکی از محبوب‌ترین و پرکاربردترین ابزارهای توسعه رابط کاربری در دنیا تبدیل شده است.

مطالعه بیشتر: کار با hookها در React

4 اشتباه رایج در هنگام استفاده از useState در React

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

اشتباه اول: نادیده گرفتن مقدار قبلی

یکی از اشتباهاتی که هنگام استفاده از هوک (Hook) در ری اکت رخ می‌دهد، نادیده گرفتن و فراموش کردن وضعیت قبلی زمان به‌روزرسانی است. این اشتباه می‌تواند باعث بروز رفتارهای غیرمنتظره شود، مخصوصا در زمان‌هایی که به‌روزرسانی سریع یا چندگانه صورت می‌گیرد.

درک این مشکل: فرض کنید که در حال ساخت یک شمارنده در ری اکت هستید و هدف اصلی شما این است که هر بار با کلیک بر روی دکمه، شمارش یک عدد افزایش پیدا کند. یک رویکرد ساده ممکن است این باشد که فقط 1 را به مقدار فعلی وضعیت اضافه کنید. اما این کار می‌تواند برای شما مشکل‌ساز باشد.

import React, { useState } from 'react';

const CounterComponent = () => {
  const [counter, setCounter] = useState(0);

  const incrementCounter = () => {
    setCounter(counter + 1); // Might not always work as expected
  };

  return (
    <div>
      <p>Counter: {counter}</p>
      <button onClick={incrementCounter}>Increment</button>
    </div>
  );
};

export default CounterComponent;

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

حل مشکل: برای اینکه بتوانید از این مشکل جلوگیری کنید، باید از فرم تابعی متد setCounter استفاده کنید. این نسخه یک تابع را به عنوان آرگومان دریافت می‌کند که در ری اکت آن را با جدیدترین مقدار وضعیت فراخوانی می‌کند و به شما این اطمینان را می‌دهد که همیشه با آخرین مقدار وضعیت کار می‌کنید.

import React, { useState } from 'react';

const CounterComponent = () => {
  const [counter, setCounter] = useState(0);

  const incrementCounter = () => {
    setCounter(prevCounter => prevCounter + 1); // Correctly updates based on the most recent state
  };

  return (
    <div>
      <p>Counter: {counter}</p>
      <button onClick={incrementCounter}>Increment</button>
    </div>
  );
};

export default CounterComponent;

در کد بالا، incrementCounter از یک تابع برای به‌روزرسانی وضعیت استفاده می‌کند. این تابع جدیدترین وضعیت، که در این کد prevCounter است، را دریافت کرده و وضعیت به‌روزرسانی‌شده را برمی‌گرداند. این رویکرد قابل‌اطمینان است و می‌توان برای به‌روزرسانی‌های سریع یا مکرر از آن استفاده کرد.

برای ادامه مطالعه و یادگیری: آموزش راه‌اندازی برنامه React با NGINX در Docker

اشتباه دوم: تغییر دادن مستقیم state به‌جای ساختن نسخه‌ی جدید

در ری اکت، وضعیت باید به‌عنوان یک شی تغییرناپذیر (immutable) در نظر گرفته شود. یکی از اشتباهات رایج، تغییر مستقیم وضعیت است، به خصوص زمانی که با ساختار داده‌های پیچیده مانند اشیاء و آرایه‌ها کار می‌شود.

import React, { useState } from 'react';

const ProfileComponent = () => {
  const [profile, setProfile] = useState({ name: 'John', age: 30 });

  const updateAge = () => {
    profile.age = 31; // Directly mutating the state
    setProfile(profile);
  };

  return (
    <div>
      <p>Name: {profile.name}</p>
      <p>Age: {profile.age}</p>
      <button onClick={updateAge}>Update Age</button>
    </div>
  );
};

export default ProfileComponent;

این کد به صورت اشتباه شی profile را مستقیماً تغییر می‌دهد. چنین تغییراتی باعث می‌شود که ری اکت دوباره کامپوننت را رندر کند و همین امر منجر به رفتارهای غیرمنتظره می‌شود.

حل مشکل: برای اینکه بتوانید از این مشکل جلوگیری کنید، همیشه هنگام به‌روزرسانی وضعیت، یک شی یا آرایه جدیدی بسازید تا تغییرناپذیری وضعیت حفظ شود. برای این کار می‌توانید از اپراتور اسپرد (spread operator) استفاده کنید.

import React, { useState } from 'react';

const ProfileComponent = () => {
  const [profile, setProfile] = useState({ name: 'John', age: 30 });

  const updateAge = () => {
    setProfile({...profile, age: 31}); // Correctly updating the state
  };

  return (
    <div>
      <p>Name: {profile.name}</p>
      <p>Age: {profile.age}</p>
      <button onClick={updateAge}>Update Age</button>
    </div>
  );
};

export default ProfileComponent;

در کد بالا، updateAge با استفاده از اپراتور اسپرد (spread operator)، یک شی جدید از profile می‌سازد که مقدار سن را در آن به‌روزرسانی می‌کند. به این ترتیب، اصل تغییرناپذیری وضعیت (state immutability) حفظ می‌شود.

مطالعه بیشتر: معرفی هاست رایگان React

اشتباه سوم: درک نا درست از به روز رسانی های غیر هم زمان

به‌روزرسانی وضعیت در ری اکت با استفاده از useState به صورت غیرهمزمان (asynchronous) انجام می‌شود. این موضوع معمولاً باعث می‌شود که شما دچار سردرگمی شوید، مخصوصا در زمانی که چند به‌روزرسانی پشت سر هم انجام می‌شود. بسیاری از توسعه‌دهندگان انتظار دارند که وضعیت بلافاصله بعد از فراخوانی setState تغییر کند، اما در واقعیت، ری اکت برای بهبود عملکرد، تمامی این به‌روزرسانی‌ها را با هم گروه‌بندی (batch) می‌کند.

import React, { useState } from 'react';

const AsyncCounterComponent = () => {
  const [count, setCount] = useState(0);

  const incrementCount = () => {
    setCount(count + 1);
    setCount(count + 1);
    // Developer expects count to be incremented twice
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment Count</button>
    </div>
  );
};

export default AsyncCounterComponent;

در این مثال، توسعه‌دهنده قصد دارد که مقدار شمارنده را به جای یک بار، دوبار افزایش دهد. اما به دلیل غیرهمزمان بودن به‌روزرسانی وضعیت در ری اکت، هر دو فراخوانی setCount بر اساس یک مقدار اولیه انجام می‌شود. در نتیجه شمارنده‌ها فقط یک بار افزایش پیدا می‌کنند.

حل مشکل: برای اینکه به‌روزرسانی غیرهمزمان به درستی و اصولی انجام شود، باید از فرم تابعی setCount استفاده کنید. این روش به شما اطمینان می‌دهد که هر به‌روزرسانی بر اساس جدیدترین مقدار وضعیت انجام می‌شود.

import React, { useState } from 'react';

const AsyncCounterComponent = () => {
  const [count, setCount] = useState(0);

  const incrementCount = () => {
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1);
    // Now each update correctly depends on the most recent state
  };
  // Optional: Use useEffect to see the updated state
  useEffect(() => {
    console.log(count); // 2
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment Count</button>
    </div>
  );
};

export default AsyncCounterComponent;

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

همین الان، بدون کمترین پیچیدگی، سرور مجازی خودتون رو در کمتر از ۳۰ ثانیه، راه‌اندازی کنید.
✅ عملکرد پایدار ✅ ترافیک نامحدود ✅ هزینه به‌صرفه
خرید سرور مجازی ابری

اشتباه چهارم: استفاده نادرست از state برای داده های قابل محاسبه

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

به عنوان نمونه:

import React, { useState } from 'react';

const GreetingComponent = ({ name }) => {
  const [greeting, setGreeting] = useState(`Hello, ${name}`);

  return (
    <div>{greeting}</div>
  );
};

export default GreetingComponent;

در این مثال، استفاده از state برای مقدار greeting بسیار ضروری است، به این دلیل که این مقدار می‌تواند مستقیماً از name به دست آید.

حل مشکل: به جای ذخیره کردن چنین داده‌هایی در state، آن‌ها را مستقیماً از وضعیت یا props موجود محاسبه کنید.

import React from 'react';

const GreetingComponent = ({ name }) => {
  const greeting = `Hello, ${name}`; // Directly derived from props

  return (
    <div>{greeting}</div>
  );
};

export default GreetingComponent;

در این قطعه کد، مقدار greeting مستقیماً از prop مربوط به name محاسبه می‌شود. این کار باعث می‌شود که کامپوننت‌ها ساده‌تر شوند و از مدیریت غیرضروری state جلوگیری کند.

بیشتر بخوانید: آموزش راه‌اندازی اپلیکیشن وب Go با Docker و Nginx در اوبونتو 22.04

سوالات متداول

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

چرا باید از useState در ری‌ اکت استفاده شود؟

برای مدیریت وضعیت داخلی کامپوننت‌ها و ایجاد قابلیت واکنش‌پذیری در رابط کاربری استفاده می‌شود.

چرا مقدار state بلافاصله پس از setState تغییر نمی‌ کند؟

زیرا بروزرسانی‌های state در ری‌ اکت به‌صورت غیرهم‌زمان انجام می‌شوند و ممکن است برای بهینه‌سازی عملکرد با سایر بروزرسانی‌ها ترکیب شوند.

چگونه می‌ توان به مقدار قبلی state دسترسی داشت؟

با استفاده از فرم تابعی setState که مقدار قبلی را به عنوان آرگومان دریافت می‌کند، مانند:

setState(prev => prev + 1)

آیا تغییر مستقیم state در ری‌ اکت مجاز است؟

خیر، تغییر مستقیم state منجر به از دست رفتن قابلیت بروزرسانی رابط کاربری و ایجاد رفتارهای غیرمنتظره می‌شود.

در چه شرایطی استفاده از useState مناسب نیست؟

زمانی که مقدار مورد نظر را می‌توان به‌صورت مستقیم از props یا سایر داده‌های موجود محاسبه کرد.

تفاوت استفاده از مقدار ثابت و فرم تابعی در setState چیست؟

فرم تابعی همواره از جدیدترین مقدار state استفاده می‌کند و برای بروزرسانی‌های متوالی یا سریع، روش مطمئن تری محسوب می‌شود.

جمع بندی

استفاده درست از هوک useState در ری اکت نقش مهمی در ساخت اپلیکیشن‌های قابل اعتماد و بهینه دارد. با شناخت و پرهیز از اشتباهات رایجی مانند: نادیده گرفتن مقدار قبلی وضعیت، تغییر مستقیم state، درک نادرست از به‌روزرسانی‌های غیرهمزمان و استفاده نادرست از state برای داده‌های قابل محاسبه، می‌توان عملکرد کامپوننت‌ها را قابل پیش‌بینی‌تر و راحت‌تر کرد. رعایت این نکات، مسیر توسعه ری اکت را حرفه‌ای و کاربردی‌تر کرده است.

برای ادامه مطالعه و یادگیری: چگونه یک برنامه React را با استفاده از Nginx بر روی سرور مجازی Ubuntu نصب کنیم؟

به اشتراک بگذارید