state یکی از مهمترین مفاهیمی است که هر توسعه دهنده مدرن جاوااسکریپت باید آن را درک کند. اگر شما مفهوم state را به درستی متوجه نشده باشید، نمیتوانید برای ساختن برنامههای خود از کتابخانههای قدرتمندی مانند React به طور کامل بهره ببرید.
در این مقاله قصد داریم تا با مفهوم state آشنا شویم، بررسی کنیم که در برنامههای جاوااسکریپت به چه شکلی وجود دارد و اینکه React چگونه به ما اجازه میدهد تا با استفاده از هوکهای داخلی مانند useState راحتتر آن را مدیریت کنیم.
چیزی که ممکن است شما را شگفتزده کند این است که هر وبسایت یا برنامهای که با جاوااسکریپت ساخته میشود شامل state است. اما بطور دقیق مشخص نیست در کجا قرار دارد.
در ادامه به بررسی یک مثال مهم میپردازیم:
ما یک برنامه counter با جاوااسکریپت داریم. میخواهیم این برنامه بتواند علاوه بر اینکه مقدار فعلی count را نمایش میدهد هنگام کم شدن یا زیاد شدن عدد، تغییرات را اعمال کند و نتیجه را نیز نشان دهد.
این برنامه فقط شامل مقدار count فعلی و دو دکمه است که یکی برای افزایش تعداد و دیگری برای کاهش تعداد خواهد بود.
در ادامه کد HTML برای شروع نوشتن برنامه را قرار دادهایم:
<!DOCTYPE html> <html> <head> <title>Counter App</title> <meta charset="UTF-8" /> </head> <body> <div> <button>+ 1</button> <span>0</span> <button>- 1</button> </div> </body> </html>
به زبان ساده، state دادههایی است که باید در طول زمان در برنامه خود مدیریت کنیم.
state اغلب از طریق ورودی که توسط کاربر وارد میشود تغییر میکند و این مورد در مثال ما نیز وجود دارد.
state در برنامه counter ما چیست؟ مقدار count است.
کاربر میتواند با کلیک بر روی دکمه مربوط، مقدار state را افزایش یا کاهش دهد. آنچه مهم است این است که ما میخواهیم آن تغییرات را به کاربر نمایش دهیم.
در حالت عادی state یک مفهوم ساده به نظر میرسد، اما زمانی که به تنهایی از جاوااسکریپت استفاده میکنیم دو مشکل در مدیریت آن وجود دارد:
وقتی کاربر روی هر یک از دکمهها کلیک میکند، چگونه میتوانیم state تعداد را بهروزرسانی کنیم؟
ابتدا باید یک رفرنس برای هر المنت مشخص کنیم. برای انجام این کار در جاوااسکریپت معمولا برای هر المنت یک id منحصر به فرد تعریف میکنیم. المنت مورد نظرمان را با متد document.querySelector
انتخاب میکنیم و رفرنس را در یک متغیر محلی ذخیره میکنیم:
<!DOCTYPE html> <html> <head> <title>Counter App</title> <meta charset="UTF-8" /> </head> <body> <div> <button id="increment">+ 1</button> <span id="count">0</span> <button id="decrement">- 1</button> </div> <script> const increment = document.querySelector("#increment"); const count = document.querySelector("#count"); const decrement = document.querySelector("#decrement"); </script> </body> </html>
اکنون که به هر المنت موجود در HTML دسترسی داریم، چگونه باید با دکمه افزایش یا کاهش کار کنیم؟
ابتدا باید به event کلیک دکمه افزایش برنامه توجه کنیم. سپس هنگامی که روی دکمه کلیک میشود مقدار count فعلی را از المنتی که id به نام “count” دارد، دریافت کنیم.
برای انجام این کار، با استفاده از document API وارد فایل HTML میشویم و آن مقدار را با استفاده از count.innerText
دریافت میکنیم. باید توجه داشته باشیم که مقدار innerText یک رشته است، بنابراین ما آن را به یک عدد تبدیل میکنیم، ۱ واحد اضافه میکنیم و سپس مقدار نهایی را در count.innerText
بازنویسی میکنیم.
برای اینکه دکمه کاهش هم کار کند، دوباره همان مراحل را تکرار میکنیم. تنها تفاوتی که وجود دارد این است که باید از عبارت Number(count.innerText - 1)
استفاده کنیم.
<!DOCTYPE html> <html> <head> <title>Counter App</title> <meta charset="UTF-8" /> </head> <body> <div> <button id="increment">+ 1</button> <span id="count">0</span> <button id="decrement">- 1</button> </div> <script> const increment = document.querySelector("#increment"); const count = document.querySelector("#count"); const decrement = document.querySelector("#decrement"); increment.addEventListener("click", () => { count.innerText = Number(count.innerText) + 1; }); decrement.addEventListener("click", () => { count.innerText = Number(count.innerText) - 1; }); </script> </body> </html>
کدی که اینجا داریم خیلی طولانی نیست و کارهایی که انجام دادیم عبارتند از:
اینها دستورالعملهای سطح پایین زیادی هستند که برای اجرای برنامه ما مورد نیاز هستند، اما کمک زیادی نمیکنند تا در مورد state زیرمجموعه فکر کنیم.
همانطور که دیدیم، state در مرورگر قرار دارد. این بدان معنی است که ابتدا باید state را «پیدا کنیم» و سپس به طوری که برای کامپیوتر قابل فهم باشد، آن مقدار را بهروزرسانی کنیم.
خوشبختانه، React راه بسیار سادهتری برای بررسی و بهروزرسانی state به ما میدهد.
یکی از مزایای مهم استفاده از React برای توسعه برنامههای جاوااسکریپت این است که الگوهای بسیار آسانتری برای بهروزرسانی state در اختیار ما میگذارد.
برخلاف جاوااسکریپت معمولی، React کار دشوار بهروزرسانی آنچه کاربر میبیند را بر عهده میگیرد. تنها کاری که ما باید انجام دهیم این است که به آن بگوییم که در حال مدیریت چه stateای هستیم و مقدار جدید باید چه چیزی باشد.
در React به جای اینکه state در مرورگر قرار داشته باشد و ما هر بار برای خواندن یا بهروزرسانی مجبور شویم آن را پیدا کنیم، میتوانیم به سادگی state را در یک متغیر قرار دهیم و سپس مقدار آن متغیر را بهروزرسانی کنیم. پس از انجام این کار، بهروزرسانی به راحتی انجام شده و مقدار جدید به کاربر نمایش داده میشود.
این کل مفهوم مدیریت state در React است.
به جای استفاده از یک فایل HTML، میتوانیم تمام کدهای خود را در یک کامپوننت React بنویسیم.
این تابع دقیقا با تابع معمولی جاوااسکریپت نوشته شده است و همان عناصر HTML را با استفاده از یک سینتکس یکسان به نام JSX نمایش میدهد.
export default function Counter() { return ( <div> <button>+ 1</button> <span>0</span> <button>- 1</button> </div> ); }
در برنامه React، هنگامی که state خود را شناسایی کردیم، آن را با استفاده از یک متغیر جاوااسکریپت کنترل میکنیم.
این متغیر را میتوانیم به روشهای مختلفی تعریف کنیم. متداولترین راه برای مدیریت state، استفاده از هوک useState است.
یک هوک در React بسیار شبیه به توابع معمولی جاوااسکریپت عمل میکند. این بدان معنی است که میتوانیم آن را در بالای کامپوننت خود فراخوانی کنیم و مقدار پیشفرض را بهعنوان مقدار شروع برای برنامه counter خود ارسال کنیم.
از آنجایی که مقدار شروع برای count برابر با صفر است، ما فقط هوک را فراخوانی میکنیم و مقدار ۰ را به آن پاس میدهیم و آن مقدار در متغیر state قرار میگیرد.
import { useState } from 'react'; export default function Counter() { // the count value lives and is managed up here! const [count] = useState(0); return ( <div> <button>+ 1</button> <span>{count}</span> {/* use curly braces to output the count value: 0 */} <button>- 1</button> </div> ); }
همان طور که در کد بالا دیدیم دیگر نیازی به استفاده از count.innerText
نیست. اکنون میتوانیم با خروجی گرفتن از count، مقدار state را بخوانیم و به آن دسترسی داشته باشیم.
انتخاب نام برای متغیر state دقیقا همانند متغیرهای جاوااسکریپت است و میتوانیم آن را هر طور که میخواهیم نامگذاری کنیم. لازم نیست حتما آن را count بنامیم، از هر نام معتبر دیگری میتوانیم استفاده کنیم.
مقدار بازگشتی از useState یک آرایه است. بعد از عمل destructuring، اولین مقدار بدست آمده متغیر state و دومین مقدار تابع بهروزرسانی state است.
import { useState } from 'react'; export default function Counter() { const [count, setCount] = useState(0); return ( <div> <button>+ 1</button> <span>{count}</span> <button>- 1</button> </div> ); }
مواردی که در این بخش به آنها نیاز نداریم عبارتند از:
برای بهروزرسانی state زمانی که روی دکمهای کلیک میکنیم، پراپ onClick را به هر دکمه اضافه میکنیم. این کار به ما این امکان را میدهد که با کلیک کردن روی هر دکمه توسط کاربر، یک تابع فراخوانی شود.
برای اینکه هنگام فشردن دکمه افزایش، state بهروزرسانی شود مقدار count + 1 را در setCount قرار میدهیم. همچنین برای دکمه کاهش، مقدار count – ۱ را به setCount منتقل میکنیم.
import { useState } from 'react'; export default function Counter() { const [count, setCount] = useState(0); function incrementCount() { setCount(count + 1); } function decrementCount() { setCount(count - 1); } return ( <div> <button onClick={incrementCount}>+ 1</button> <span>{count}</span> <button onClick={decrementCount}>- 1</button> </div> ); }
این تمام کدی است که برای ایجاد یک برنامه counter با React نیاز داریم.
هنگامی که روی هر دکمهای کلیک شود state بهروزرسانی میشود. به این صورت React تمام کارهای بهروزرسانی صفحه را انجام میدهد تا کاربر بتواند state جدید را ببیند.
زمانی که از هوکهایی مانند useState برای مدیریت state استفاده میکنیم میتوانیم برنامههای سادهتر با قابلیت اعتماد بالا بسازیم که در آنها state به راحتی قابل مشاهده، خواندن و بهروزرسانی باشد. زیرا React به طور موثر از بهروزرسانی آنچه که کاربر میبیند مراقبت میکند. این موضوع یک مزیت بزرگ استفاده از React در مقابل جاوااسکریپت به حساب میآید.