استفاده از (prevState state) یا حالت قبلی در ری اکت، مبتدی و پیچیده

از پریو استیت  prevState در ری اکت چه میدانید
از پریو استیت prevState در ری اکت چه میدانید


عبارتprevState یک متغیر است. این متغیر در ری اکت به ما این امکان را می‌دهد که با استفاده از مقدار قبلی یک وضعیت (state)، به راحتی تغییراتی را اعمال کنیم. در زمینه‌های مبتدی و پیشرفته ری اکت، استفاده از prevState به منظور بهبود عملکرد و اجتناب از مشکلاتی که از تغییر مستقیم در وضعیت ممکن است ایجاد شود، بسیار حیاتی است.

چگونه از "prevState" معروف برای تغییر state ری اکت خود بدون اورراید یا بازنویسی آن استفاده کنیم!

بیایید با یک مثال ساده و معروف شروع کنیم (برنامه شمارنده)

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

import &quot./App.css&quot
import React, { useState } from &quotreact&quot
const App = () => {
const [mySuperCounter, setMySuperCounter] = useState(0);
const handleIncrement = () => {
setMySuperCounter(mySuperCounter + 1);
setMySuperCounter(mySuperCounter + 1);
setMySuperCounter(mySuperCounter + 1);
};
const handleReset = () => {
setMySuperCounter(0);
};
return (
 <div className='App'>
  <div>
   <button
   className='super-button'
   type=&quotsubmit&quot
   ={handleIncrement}>
   Incrementor
   </button>
   <button className='super-button' type='submit' ={handleReset}>
State Resettor
   </button>
  </div>
  <div>{mySuperCounter}</div>
</div>
);
};
export default App;

خوب، بیایید کدهای بالا را برای روشن تر شدن توضیح دهم:

در اینجا، ما یک کامپوننت پایه داریم که از state یا حالتی به نام «mySuperCounter» و دو دکمه تشکیل شده است: یکی برای افزایش state و دیگری برای تنظیم مجدد آن به 0 یا همان ریست.

اگر متد "handleIncrement" را بررسی کنیم، ممکن است به نظر برسد که هر بار که روی دکمه "Incrementor" کلیک می کنیم، state به اندازه 3 واحد افزایش می یابد. اما رفتار واقعی متفاوت است. این به این دلیل است که تابع setState ما state قبلی را لغو می کند و یک state جدید ایجاد می کند. به همین دلیل، هنگامی که روی دکمه کلیک می‌کنیم، وضعیت اولیه سه بار با مقدار یک بازنویسی می‌شود. به عبارت دیگر، نتیجه ناخواسته‌ای که به آن می‌رسیم، یک می‌باشد.

اکنون، بیایید بررسی کنیم که چگونه می توانیم به صورت درستی به حالت قبلی بیافزاییم:

در اینجا کد مربوط به متد handleIncrement آمده است:

const handleIncrement = () => {
setMySuperCounter((prev) => prev + 1);
setMySuperCounter((prev) => prev + 1);
setMySuperCounter((prev) => prev + 1);
};

به راهمان ادامه دهیم! حالا، هنگامی که روی دکمه "Incrementor" کلیک می‌کنیم، شمارنده ما به ازای هر کلیک به ۳ افزایش می‌یابد. چرا؟ این به دلیل آرگومان "prev" است که به تابع بازخوانی `setState` در بالاتر ما ارسال شده است.

در موردی که با آن روبرو هستیم، "prev" نشان دهنده state یا حالت قبلی است. بنابراین خط به خط 0 را با 1 و سپس 1 را با 1 و در نهایت 2 را با 1 جمع(ریاضی) میکنیم که در مجموع 3 به دست می آید.




این یک مثال اساسی برای نشان دادن این بود که چگونه آرگومان "prev" به ما کمک می کند تا state یا حالت را به درستی به روز کنیم. حال، بیایید به عمق یک مثال پیچیده تر شیرجه بزنیم!



افزودن کلید/مقدار از یک آرایه به یک آرایه از اشیاء:

ابتدا، یک فایل به نام `sections.js` را ایجاد کنید:

بیایید یک فراخوانی API را با استفاده از یک promise شبیه سازی کنیم:

// sections.js
const mySections = () => {
 return Promise.resolve([
  { id: 1, title: &quotMy First Section&quot },
  { id: 2, title: &quotMy Second Section&quot },
] );
};
export default mySections;

سپس، فایل `App.js` را به گونه‌ای تغییر میدهم که فراخوانی API را با استفاده از هوک `useEffect` انجام داده و نتیجه را در یک متغیر وضعیت ذخیره کند:

// App.js
import &quot./App.css&quot
import React, { useEffect, useState } from &quotreact&quot
import mySections from &quot./sections&quot
const App = () => {
 const [sections, setSections] = useState([]);
  useEffect(() => {
   const loadSections = async () => {
    return await mySections();
   };
   loadSections().then((res) => {
    setSections(res);
   });
  }, []);
 return <div className=&quotApp&quot></div>;
};
export default App;

سپس، یک Promise دیگر در یک فایل جداگانه به نام `tools.js` بسازید تا یک فراخوانی API اضافی شبیه‌سازی شود. این‌بار، ما داده‌هایی را دریافت می‌کنیم که می‌خواهم آن‌ها را در بخش‌های ذکر شده از قبل، بر اساس `section_id`، ارسال کنم:


// tools.js
const myTools = () => {
return Promise.resolve([
{ id: 1, title: &quotMy Super first tools&quot, section_id: 1 },
{ id: 2, title: &quotMy Super second tools&quot, section_id: 2 },
{ id: 3, title: &quotMy Super third tools&quot, section_id: 1 },
{ id: 4, title: &quotMy Super fourth tools&quot, section_id: 2 },
{ id: 5, title: &quotMy Super fifth tools&quot, section_id: 1 },
{ id: 6, title: &quotMy Super sixth tools&quot, section_id: 2 },
{ id: 7, title: &quotMy Super seventh tools&quot, section_id: 1 },
{ id: 8, title: &quotMy Super eighth tools&quot, section_id: 2 },
]);
};
export default myTools;


حالا، فایل `App.js` را جوری تغییر میدهم تا این تغییرات را اعمال کند:


//App.js
const App = () => {
 const [sections, setSections] = useState([]);
  useEffect(() => {
   const loadSections = async () => {
    return await mySections();
   };
   loadSections().then((res) => {
    setSections(res);
   });
   const loadToolsIntoSections = async () => {
    return await myTools();
   };
   loadToolsIntoSections().then((response) => {
     setSections((prev) => {
      return prev.map((section) => {
       return {
        ...section,
        tools: response.filter((tool) => {
         return tool.section_id === section.id;
        }),
       };
      });
     });
    });
   }, []);
   return <div className=&quotApp&quot></div>;
};
export default App;


در `App.js` تغییر یافته، من متد `loadToolsIntoSections` را فراخوانی می‌کنم که یک فراخوانی API دیگر را شبیه‌سازی می‌کند. من از متد `setSections` را مجدداً استفاده می‌کنم و آرگومان "prev" را به تابع بازخوانی می‌فرستم تا مطمئن شوم که وضعیت قبلی را حفظ میکنم.

سپس روی آرایه sections یک حلقه map می‌زنیم تا از طریق هر ابجکت درون آن حرکت کنیم. با استفاده از عملگریا اپراتور spread، یک ابجکت جدید ایجاد کرده و یک کلید اضافی به نام "tools" اضافه می‌کنیم.

برای پر کردن کلید "tools"، ما response حاصل از فراخوانی API خود را فیلتر می‌کنیم. ما section_id هر ابزار را با id بخش فعلی مقایسه می‌کنیم. با این کار، هر ابزار را به درستی در داخل بخش مربوطه‌اش ارسال می‌کنیم.

این رویکرد به ما این امکان را می‌دهد که ابزارها را با بخش‌های مربوط به آن‌ها به طور موثر ارتباط دهیم. امیدوارم که این توضیح به شما کمک کند که چگونه از prevState به طور موثر استفاده کنید! با استفاده از آرگومان "prev" ارائه شده در تابع بازخوانی setState، به راحتی می‌توانید وضعیت قبلی را حفظ و به‌روز رسانی کنید. این رویکرد مفید است زمانی که نیاز به انجام تغییرات بر اساس وضعیت قبلی دارید و می‌خواهید از مدیریت و ارسال داده‌ها به درستی اطمینان حاصل کنید. اگر سوال دیگری دارید، راحت باشید و بپرسید!