هوک useState ری اکت چیست ؟ بررسی تخصصی useState در ری اکت !
هوک useState ری اکت به ما این امکان رو میده که حالت ها و مقادیر کامپوننت خودمون رو در جایی ذخیره کنیم. این حالت ها (stateها) میتونن از هر نوعی باشن .با ذخیره کردن این state ها ( به کمک useState در ری اکت ) میتونیم تو کل اون کامپوننت ازشون مثل یه متغیر استفاده کنیم و هر زمان نیاز داشتیم مقدارشون رو بروزرسانی کنیم .
با فرانت اندی همراه باشید تا هوک useState در ری اکت رو بررسی کنیم 🙂
هوک useState ری اکت چیست ؟
هوک useState یکی از مهمترین هوک های ری اکت هست که به ما اجازه میده حالت های کامپوننت خودمون رو ذخیره و مدیریت کنیم . حالا شاید بپرسید حالت کامپوننت یعنی چی ؟
فرض کنید توی کامپوننت خودمون باید نام کاربر یا شماره تلفنش رو در جایی ذخیره کنیم . خب هرکدوم از اینها یک حالت ( state ) هستن که هوک useState ری اکت به ما امکان ذخیره و بروزرسانی این مقادیر رو میده.
برای ذخیره کردن نام کاربر باید بصورت زیر عمل کنیم :
const [name,setName] = useState('احمد')
و سپس برای استفاده از نام کاربر تو کامپوننت خودمون ، باید از name استفاده کنیم . مثل مثال زیر :
{name}
برای تغییر یا بروزرسانی مقدار name به یک مقدار جدید ( مثلا تغییر احمد به حسین ) باید بصورت زیر عمل کنیم :
setName('حسین')
در واقع useState در React.به ما 2 امکان میده :
- امکان خواندن مقدار ذخیره شده .
- امکان بروزرسانی مقدار ذخیره شده.
هوک useState ری اکت چه مقادیری رو میتونه ذخیره کنه ؟
هوک useState در React به ما اجازه ذخیره هر نوع مقداری با هر نوعی رو میده !
مثلا شما میتونید انواع مختلف دیتا های primitive مثل String , Number , Boolean رو داخل useState در ری اکت ذخیره کنید . همچنین امکان ذخیره کردن دیتا های Complex مثل Array و Object ، تابع ، و دیتا تایپ های اختصاصی روهم دارید.
یا بزارید اینجوری بگم :
هرچیزی که داخل متغیر های جاوااسکریپت میتونید ذخیره کنید ، داخل هوک useState هم میتونید 🙂
چطور Object و Array ذخیره شده در State رو بروزرسانی کنیم ؟
بروزرسانی مقادیر ذخیره شده در state ها خیلی آسونن ! ( البته بروزرسانی Object و Array کمی تفاوت داره )
مثلا برای آپدیت کردن state با نوع number ، string و boolean بصورت زیر باید عمل کنیم :
بروزرسانی State با نوع Number !
//My State
const [age,setAge]=useState(18)
// Update My State
setAge(20)
بروزرسانی State با نوع String !
//My State
const [name,setName]=useState('علی')
// Update My State
setName('ممد')
بروزرسانی State با نوع Boolean !
//My State
const [premium,setPremium]=useState(false)
// Update My State
setPremium(true)
اما بروزرسانی Object و Array کمی متفاوت تره !
تو ری اکت انواع مختلف دیتا رو میشه بصورت مستقیم بروزرسانی کرد ( مثل مثال های بالا )
اما برای Object و Array نمیشه مستقیما بروزرسانی رو انجام داد . ( بخاطر بحث immutability که بعدا راجبش صحبت میکنیم )
برای بروزرسانی Object یا Array باید بصورت زیر عمل کنید :
یک کپی از Object یا Array موجود در state بگیرید .
تغییرات خودتون رو روی اون Object یا Array کپی شده اعمال کنید .
حالا توسط setState آبجکت یا آرایه بروز شده رو در state ذخیره کنید .
تو دستورالعمل بالا ما مستقیما مقدار State خودمون با نوع Object یا Array رو آپدیت نمیکنیم !
یک کپی از اون مقدار میگیریم و هر تغییری که لازم داریم رو روی اون مقدار کپی شده لحاظ میکنیم .
حالا مقدار کپی شده که تغییرات رو هم شامل شده ، توسط setState جایگزین مقدار قبلی در state میکنیم .
تو مثال زیر یه State با نوع Object رو بروزرسانی میکنیم :
const [state, setState] = useState({ name: 'Fatemeh', age: 21 });
const updateAge = () => {
setState({ ...state, age: 22 });
};
تو مثال بالا یه State داریم که یک Object به عنوان مقدار اولیه ( InitialState ) بهش دادیم . این آبجکت شامل نام و سن هست که نام از نوع رشته و سن از نوع عدد هستن.
تابع updateAge برای بروزرسانی اطلاعات این State هست که داخلش setState رو صدا زدیم .
با state… میتونیم یک کپی از مقدار state بگیریم ، حالا چون مقدار age تغییر کرده پس در کنارش مقدار جدید رو هم قرار میدیم .
یعنی تو خط 4 گفتیم : از هرچی تو state هست یه کپی بگیر ، حالا مقدار age رو توی ورژن کپی شده تغییر بده . در نهایت با setState این مقدار بروز شده رو set کن .
تو مثال زیر یه state با نوع Array رو بروزرسانی میکنیم :
const [array, setArray] = useState([1, 2, 3, 4, 5]);
const addItem = () => {
setArray([...array, 6]);
};
تو مثال بالا یک state از نوع Array داریم .
تو خط 4 یک کپی از array گرفتیم و مقدار 6 رو به این آرایه اضافه کردیم و در نهایت توسط setArray این مقدار بروزر شده رو set کردیم .
چه زمانی باید از useState در ری اکت استفاده کنیم ؟
بطور کل زمانیکه میخوایم حالت ها یا مقادیر مرتبط به یک کامپوننت رو بصورت داخلی ذخیره کنیم ، باید از هوک useState در ری اکت استفاده کنیم .
اما اگه حالت یا وضعیتی که میخوایم ذخیره کنیم داخلی نیست و گلوبال هست ، باید از State Management هایی مثل Redux استفاده کنیم. ( داخلی نیست یعنی از یه state تو کل اپیکیشن و کامپوننت های مختلف استفاده کنیم )
چطور از useState در React استفاده کنیم ؟
برای استفاده از useState در React باید اون رو import کنیم ( فراخوانی کنیم ) :
import React, { useState } from 'react';
مقدار اولیه useState یا همون initialState چیه ؟
همونطور که قبلا هم گفتیم ، موقع استفاده از هوک useState باید یک مقدار اولیه بهش بدیم .
اما یه جاهایی از مقدار اولیه خبر نداریم !!
مثلا قراره از یک API ، مقداری رو بگیرید و داخل state بعنوان initialState قرار بدید . و خب چون نمیدونیم مقداری که اون API میخواد برگردونه چیه و چقدر زمان میبره ، نمیتونیم موقع تعریف بهش مقداری رو به عنوان مقدار اولیه بدیم .
در اینجا از تکنیکی به عنوان Lazily Initialize استفاده میکنیم .
در واقع Lazily Initialize مواقعی کاربرد داره که مقدار اولیه ما با تاخیر باید Initialize ( مقدار دهی اولیه ) بشه .
تو مثال زیر از useState در ریکت استفاده کردیم اما بعنوان مقدار اولیه ، یک Function بهش دادیم :
const userDetail= () => {
const [state,setState] = useState( () => myApiCallFunction() );
}
تو مثال بالا یه نکته مهم وجود داره ، اینکه مقدار اولیه ای که با تکنیک Lazily Initialize قرار دادیم ، فقط در render اولیه قرار میگیره.
مقدار دهی اولیه State هایی که نوع عددی یا رشته دارن!
اگه state ما از نوع String یا Number هست، میتونیم عدد 0 یا یک رشته خالی رو به عنوان مقدار اولیه useState در ری اکت بهش پاس بدیم.
بعنی برای State هایی که از نوع String هستن :
const [string,setString] = useState('')
و برای State هایی که از نوع Number هستن :
const [number,setNumber] = useState(0)
بروزرسانی State با setState در ری اکت !
هوک useState از ما 2 آرگومان میگیره . مقدار اول برای خواندن مقدار اون state و مقدار دوم یک تابع برای بروزرسانی مقدار اون state هست .
تو مثال زیر یک کامپوننت به اسم User داریم و قراره نام کاربر رو داخل یک State به نام name ذخیره کنیم . دقت کنید که این مقدار توسط یک Input از خود کاربر دریافت میشه و توسط onChange داخل state قرار میگیره .
const User = () => {
const [name,setName] = useState('');
return (
setName(e.target.value)}
placeholder="نام خودتون رو وارد کنید"
/>
میباشد.{name}نام شما
);
}; //
گاهی اوغات نیاز میشه که state خودمون رو با توجه به مقدار قبلی اون state بروزرسانی کنیم .
مثلا میخوایم با هربار کلیک روی دکمه ، مقدار state به علاوه 1 بشه . انجام اینکار مستلزم بررسی مقدار قبلی state هست .
تو مثال زیر همون مثال بالایی رو اوردیم ، با این تفاوت که قراره با توجه به مقدار قبلی state ، عملیات setState رو انجام بدیم :
const User = () => {
const [name,setName] = useState('');
return (
setName(prev=>prev+e.target.value)}
placeholder="نام خودتون رو وارد کنید"
/>
میباشد.{name}نام شما
);
}; //
استفاده از هوک useState در React برای ذخیره کردن Object
چند تا نکته تخصصی و مهم راجب State هایی که نوع Object دارن وجود داره که هرکسی به این نکات توجه نمیکنه.
نکته اول :
برای اینکه نکته اول رو بگم ، State زیر که نوعش Object هست رو در نظر بگیرید :
const [user,setUser]=useState({name:'Ahmad'',phone:09111111111});
حالا فرض کنید کد زیر رو اجرا کنیم یعنی setUser با همون مقدار user !
setUser({...user})
شاید فکر کنین اینجا re-Render صورت میگیره اما اینطور نیست .در واقع ری اکت تو پشت صحنه از تابع ()Object.is استفاده میکنه و متوجه میشه که State جدید با State قبلی یکسانه ! پس re-Redner صورت نمیگیره 🙂
نکته دوم :
برای state هایی که نوع Object داخلشون ذخیره کردیم ، نمیتونیم بصورت مستقیم setState رو انجام بدیم و حتما باید از تکنیک بروزرسانی State بصورت غیرمستقیم استفاده کنیم .
این نکته رو اوایل همین مقاله + کد نمونه و توضیحش مطرح کردیم . پس بریم سراغ نکته سوم.
نکته سوم :
فرض کنید state زیر رو داریم و میخوایم فقط name این آبجکت رو ویرایش کنیم :
const [user,setUser]=useState({name:'Ahmad'',phone:09111111111});
حالا اگه کد زیر رو اجرا کنیم :
setUser({...user,name:'اکرم'})
یه اتفاق عجیب میوفته .
ما فقط name این آبجکت رو ویرایش کردیم و توقع داریم ری اکت فقط name این آبجکت رو ویرایش کنه.
اما React تمام آبجکت جدید رو با آبجکت قدیمی جایگزین میکنه و کاری نداره که کدوم خصوصیاتش تغییر کرده و کدوم خصوصیاتش تغییر نکرده.
چند نکته مهم راجب useState ری اکت
اگه قصد استفاده از هوک useState در ری اکت رو دارین ، باید قوانین این هوک رو هم بدونید .
اول از همه اینکه useState در ریکت یکی از هوک های ری اکت هست پس تمام قوانین هوک های ری اکت ، شامل این هوک هم میشه . مثل سایر هوک های ری اکت ( اعم از هوک useMemo یا هر هوک دیگه ای )
قوانینی مثل :
- فقط تو Top Level کامپوننت ازشون استفاده کنید .
- فقط تو کامپوننت های فانکشنال ازشون استفاده کنید ( Not Class Components )
به عنوان یه مثال کامل ، بیاید یه کامپوننت به اسم Form بسازیم و اطلاعات کاربر رو داخل state ذخیره کنیم :
import React, { useState }from 'react'
const Form = () => {
const [user, setUser] = useState('') //برای ذخیره نام کاربر
const [email, setEmail] = useState('')// برای ذخیره کردن ایمیل کاربر
const handleSubmit = (e) => {
console.log("این زمانی اجرا میشه که فرم سابمیت بشه")
}
return (
)
}
export default Form;
تغییر state باعث رندر مجدد کامپوننت ما میشه !
زمانیکه ما state خودمون رو تغییر میدیم، کامپوننت ما re-render میشه. این یکی از قوانین خود React هست و ما نمیتونیم جلوی این قضیه رو بگیریم.
درواقع re-render شدن کامپوننت پس از تغییر State به این دلیل صورت میگیره که کامپوننت بتونه اطلاعات جدید ( state جدید ) رو در صفحه نمایش بده.
نباید بزاریم State ما خیلی بزرگ بشه !
زمانیکه از هوک useState در ری اکت استفاده میکنیم، ممکنه نیاز داشته باشیم که داخلش یک Object ذخیره کنیم. اما نباید اجازه بدیم این Object خیلی بزرگ بشه.
مثلا اگه Object ما برای ذخیره کردن لیست کاربران هست، میتونیم 2 یا چند هوک useState تعریف کنیم و داخل هر useState کاربران مرتبط با هم رو ذخیره کنیم. مثلا داخل useState کاربران معمولی و داخل useState دوم کاربران ویژه!
اینکار با این هدف صورت میگیره که Object ذخیره شده داخل useState در React خیلی بزرگ و سنگین نشه.
بروزرسانی State بر اساس State قبلی !
اگه میخوایم State خودمون رو بر اساس State قبلی تغییر بدیم خیلی خیلی ضروریه که بصورت زیر اینکار رو انجام بدیم :
setState(oldState => newState)
مثلا فرض کنیم داخل State یک عدد ذخیره میکنیم و میخوایم عدد فعلی State رو به علاوه 4 کنیم. چون این بروزرسانی State با توجه به مقدار قبلی State انجام میشه حتما باید از سینتکس بالا استفاده کنیم.
انجام اینکار با این هدف صورت میگیره که مطمئن بشیم داریم آخرین مقدار State رو آپدیت میکنیم.
رفع مشکلات و خطا های مرتبط با useState در ری اکت !
اگه useState شما دچار مشکل شده و مقدار اشتباهی داخلش قرار میگیره یا بروزرسانی نمیشه یا هر مشکل دیگه، اصلا نگران نباشید!
ما میتونیم به کمک هوک useEffect در ری اکت مشکلش رو برطرف کنیم.
کافیه یک useEffect تعریف کنیم و به عنوان Dependencies، خود State رو قرار بدیم تا با هر تغییر State، یکبار useEffect اجرا بشه و برای ما console.log بگیره :
useEffect(() => {
console.log(state);
}, [state])
انجام اینکار باعث میشه در شرایط مختلف ( render های مختلف ) مقدار ذخیره شده در State رو بتونیم ببینیم و متوجه بشیم چه زمانی مقدار غیرصحیح یا اشتباه داخل State ذخیره میشه.
هوک useReducer برای مدیریت State های پیچیده تر !
اگه State ما خیلی پیچیدس و ساده نیست، ما میتونیم از هوک useReducer در ری اکت برای مدیریت State پیچیده استفاده کنیم. اگه State پیچیده دارید و با این هوک آشنا نیستید، روی لینک آبی رنگ بالا کلیک کنید و درمورد این هوک بیشتر بخونید.
بطور کل این هوک اجازه میده خیلی بهتر و حرفه ای تر بتونیم State خودمون رو مدیریت کنیم.
تعریف و نگهداری هوک useState در ری اکت !
ما باید useState خودمون رو در جای درست تعریف و نگهداری کنیم. در حقیقت بهترین مکان برای تعریف useState، داخل خود کامپوننتی هست که میخوایم حالت ها یا مقادیرش رو ذخیره کنیم.
ترجیحا باید سعی کنیم که داده های یک کامپوننت رو در کامپوننت فرزند یا پدر ذخیره نکنیم ( هرچند گاهی اوغات نیاز داریم این کار رو بکنیم، در چنین مواقعی مشکلی نیست )
بهینه سازی تغییرات State به سادگی !
گاهی اوغات پیش میاد که تغییر State ما، محاسبات سنگینی داره.
برخی محاسبات سبک هستن، مثل setState کردن یک عدد یا یک رشته ..
اما گاهی اوغات میخوایم روی یک آرایه map بزنیم، یکسری محاسبات انجام بدیم و درنهایت نتیجه رو setState کنیم.
در چنین مواقعی که محاسبات سنگینی داریم باید از هوک useMemo در ری اکت استفاده کنیم. اگه با این هوک آشنا نیستید روی لینک آبی رنگ کلیک کنید و بیشتر درموردش بخونید چون تو بهینه تر شدن کامپوننت شما خیلی خیلی موثره!
هیچوقت State خودمون رو نباید مستقیما آپدیت کنیم!
ما نمیتونیم State خودمون رو بصورت مستقیم آپدیت کنیم. تنها روش بروزرسانی State، استفاده از تابع setter هوک useState در ری اکت هست.
بطور مثال State زیر رو در نظر بگیرید :
const [name,setName] = useState('')
تو State بالا ما نمیتونیم مقدار name رو مستقیما بروزرسانی کنیم. مثل name=ali
تنها راه بروزرسانی این state استفاده از تابع setName هست. دلیل این موضوع برمیگرده به مباحث immutability که میگه ما نمیتونیم Object رو بصورت مستقیم تغییر بدیم.
جمع بندی
هوک ()useState ری اکت ، به ما امکان ذخیره کردن مقادیر/حالت های مورد نیاز تو کامپوننت هایی که نوع Function دارن رو میده.
تو این مقاله خیلی جامع این هوک رو بررسی کردیم و تمام نکاتی که باید درمورد این هوک میدونستیم رو بررسی کردیم. با این حال هر سوال یا مشکلی درمورد useState در ریکت داشتید تو کامنت های همین مقاله بپرسین 🙂
امیدوارم هوک useState در ری اکت رو خیلی خوب متوجه شده باشید 🙂
هوک useState ری اکت به ما اجازه میده انواع مختلف داده رو تو کامپوننت های خودمون ذخیره و هر زمان لازم بود ، ویرایشش کنیم .
خیر ! هوک ها فقط قابلیت استفاده در Functional Component ها رو دارن.
درباره احمد احمدنژاد
من یه برنامه نویس و توسعه دهنده وب هستم که عاشق دنیای صفر و یکم❤️
نوشتههای بیشتر از احمد احمدنژاد12 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
سلام و درود خدا
عالی بود پر از نکته
سلام مصطفی جان خیلی خوشحالم که برات مفید واقع شده و ممنونم از نظری که گذاشتی 🙂 موفق باشی
عالی بود خدایی خیلی خوب توضیح دادی حال کردم
سلام رفیق 🙂 خوشحالم که برات مفید واقع شده و مرسی از نظری که گذاشتی 🙂
موفق باشی
من یه مشکلی دارم
میشه لطفا راهنماییم کنین که چه زمانی تشخیص داده میشه لازمه یه useState جدید بنویسین
و
کجا میتونین مقدارش رو مثلا از آرایه به آبجکت تغییر بدین بعد از اون فقط از آبجکت استفاده بشه(متفاوت از مقدار اولیه)
سلام فارا جان
بابت تشخیص زمان نیاز بهتره 3 فاکتور رو در نظر بگیری:
1 ) هرموقع میخوایم یک state مستقل رو ذخیره کنیم : مثلا اگه 2 فیلد مختلف داریم که نیازه مقداراشون جداگونه ذخیره بشه باید برای هرکدوم یک useState جدا تعریف کنیم.
2 ) وقتی میخوایم کدمون ساده و خواناتر باشه : نگهداری مقدارها در useState های جداگونه کمک میکنه که کد ما خوانا تر و ساده تر باشه.
3 ) میدونیم که تغییر مقدار state باعث re-render کامپوننت های مرتبط با اون state میشه. استفاده از چندین useState مستقل میتونه باعث کاهش تعداد رندرهای غیرضروری بشه، زیرا تغییر یک state خاص باعث رندر شدن کامپوننتهای مرتبط با اون state میشه!
مفید بود ممنون
سلام امین جان خوشحالم که برات مفید واقع شده موفق باشی 🙂
سلام بزرگوار.وقتتون بخیر.خیلی ساده و قابل فهم توضیح دادی.متشکرم
سلام سجاد جان
خوشحالم که برات مفید واقع شده 🙂
موفق باشی
من با تمام hook ها درگیر بودم ممنونم که اینقدر قشنگ مطلب رو جا انداختین
سلام سمیرا جان
خیلی خوشحالم که برات مفید واقع شده 🙂
موفق باشی