مقالات

استفاده از حالت اولیه تنبل و به روز رسانی عملکرد


اگر مدتی با React کار می‌کنید، احتمالاً استفاده کرده‌اید useState.
در اینجا یک مثال سریع API آمده است:

function Counter() {
	const [count, setCount] = React.useState(0)
	const increment = () => setCount(count + 1)
	return button onClick={increment}>{count}button>
}

بنابراین، شما تماس بگیرید useState با مقدار حالت اولیه و یک آرایه برمی گرداند
با مقدار این حالت و مکانیزمی برای به روز رسانی آن (که نامیده می شود
“دولت dispatch تابع”). وقتی تابع وضعیت ارسال را فراخوانی می کنید، شما
مقدار حالت جدید را می گذراند و این باعث رندر مجدد مولفه می شود
که باعث می شود useState دوباره برای بازیابی مقدار وضعیت جدید فراخوانی شود و
تابع ارسال مجدد

این یکی از اولین چیزهایی است که هنگام ورود به ایالت در مورد آن یاد می گیرید
واکنش نشان دهید (حداقل اگر باشد
از دوره رایگان من یاد بگیرید). اما وجود دارد
ویژگی کمتر شناخته شده هر دو useState تماس بگیرید و dispatch تابع
که گاهی اوقات می تواند مفید باشد:

function Counter() {
	const [count, setCount] = React.useState(() => 0)
	const increment = () => setCount((previousCount) => previousCount + 1)
	return button onClick={increment}>{count}button>
}

تفاوت این است useState در این مثال با a نامیده می شود تابع
که برمی گردد
حالت اولیه (به جای عبور از حالت اولیه)
و setCount (ارسال) با تابعی فراخوانی می شود که تابع قبلی را می پذیرد
یک مقدار را اعلام می کند و مقدار جدید را برمی گرداند. این درست مثل کار می کند
مثال قبلی، اما تفاوت های ظریفی وجود دارد که در این مورد به آنها خواهیم پرداخت
پستی که در موردش آموزش میدم
دوره رایگان React من نیز اما آنها از من می پرسند
به اندازه ای که تصمیم گرفتم در مورد آن نیز بنویسم.

اگر الف اضافه کنید console.log به بدنه تابع تابع شمارنده،
متوجه خواهید شد که هر بار که روی دکمه کلیک می شود این تابع اجرا می شود. این
منطقی است زیرا تابع شمارنده شما در هر مرحله رندر و اجرا می شود
با کلیک بر روی دکمه، به روز رسانی حالت فعال می شود که باعث بازپرداخت می شود. یکی
چیزی که باید در نظر داشت این است که اگر بدن عملکردی کار کند، این یعنی همه چیز
کد داخل آن نیز اجرا می شود. یعنی هر متغیری که ایجاد می کنید یا
آرگومان هایی که پاس می کنید در هر رندر ایجاد و ارزیابی می شوند. معمولاً اینطور نیست
مشکل بزرگی است زیرا موتورهای جاوا اسکریپت بسیار سریع هستند و می توانند برای این کار بهینه شوند
چیزی شبیه به آن بنابراین چیزی شبیه به این مشکلی نخواهد داشت:

const initialState = 0
const [count, setCount] = React.useState(initialState)

اما اگر مقدار اولیه ایالت شما از نظر محاسباتی گران باشد چه؟

const initialState = calculateSomethingExpensive(props)
const [count, setCount] = React.useState(initialState)

یا به طور عملی تر، چه می شد اگر مجبور به خواندن بودید localStorage که هست
عملیات IO؟

const initialState = Number(window.localStorage.getItem('count'))
const [count, setCount] = React.useState(initialState)

به یاد داشته باشید که تنها زمانی که React نیاز دارد اولیه شرط است در ابتدا 😉یعنی واقعاً فقط به حالت اولیه در اولین رندر نیاز دارد. اما چون
بدن تابع ما هر بار که یک رندر مجدد از مؤلفه ما وجود دارد اجرا می شود، ما خاتمه می دهیم
اجرای این کد در هر رندر، حتی اگر مقدار آن استفاده نشده یا مورد نیاز باشد.

این همان چیزی است که مقداردهی اولیه تنبل است. به شما امکان می دهد این را تنظیم کنید
کد در یک تابع:

const getInitialState = () => Number(window.localStorage.getItem('count'))
const [count, setCount] = React.useState(getInitialState)

ایجاد یک ویژگی سریع است. حتی اگر کاری که تابع انجام می دهد محاسباتی باشد
گران قیمت بنابراین جریمه عملکرد را فقط زمانی پرداخت می کنید یک تماس تابع
بنابراین اگر تابعی را به useState، React فقط زمانی تابع را فراخوانی می کند
به مقدار اولیه نیاز دارد (یعنی زمانی که مؤلفه در ابتدا رندر می شود).

به این “تعداد اولیه تنبل” می گویند. این یک بهینه سازی عملکرد است. شما
من نباید زیاد از آن استفاده کنم، اما می تواند در برخی شرایط مفید باشد،
بنابراین خوب است بدانید که این یک ویژگی است که وجود دارد و شما می توانید از آن استفاده کنید
لازم است. من می‌توانم بگویم که من فقط در 2٪ مواقع از این استفاده می‌کنم. این در واقع یک تابع I نیست
اغلب استفاده کنید

این یکی کمی پیچیده تر است. ساده ترین راه برای توضیح چیست
برای با نشان دادن یک مثال است. قبل از اینکه بتوانیم تعداد خود را به روز کنیم، این را بگوییم
حالت، ما باید کاری را به صورت ناهمزمان انجام دهیم:

function DelayedCounter() {
	const [count, setCount] = React.useState(0)
	const increment = async () => {
		await doSomethingAsync()
		setCount(count + 1)
	}
	return button onClick={increment}>{count}button>
}

بیایید بگوییم که چیزی غیر همگام 500 میلی ثانیه طول می کشد. این تصویر اینجاست، روی این دکمه کلیک کنید
سه بار خیلی سریع:

اگر به اندازه کافی سریع روی آن کلیک کنید، متوجه خواهید شد که شمارنده تنها افزایش یافته است
به 1. اما این عجیب است زیرا اگر a را اضافه کنید console.log به increment
تابع، خواهید دید که سه بار (یک بار برای هر کلیک) فراخوانی می شود، بنابراین
چرا وضعیت شمارش سه بار به روز نمی شود؟

خوب، اینجاست که همه چیز پیچیده می شود. واقعیت این است که دولت است به روز شد
سه بار (یک بار برای هر کلیک)، اما اگر یک را اضافه کنید console.log(count)
درست در بالا setCount تماس بگیرید، متوجه این خواهید شد count است 0 هر بار! و همینطور
ما تماس می گیریم setCount(0 + 1) برای هر کلیک، حتی اگر واقعاً بخواهیمتعداد را افزایش دهید

پس چرا عدد است 0 هر بار؟ این به این دلیل است increment تابعی که
ما به React یک via دادیم onClick حمایت از این button “بسته”
ارزش از count در زمان ایجاد آن شما می توانید
در mdn.io/closure درباره بسته شدن اطلاعات بیشتر بیاموزید، اما در
به طور خلاصه، هنگامی که یک تابع ایجاد می شود، به متغیرهای تعریف شده خارج از آن دسترسی دارد، حتی اگر آنچه که آن متغیرها به آنها اختصاص داده شده اند تغییر کند.

مشکل این است که ما در واقع دقیقاً همان چیزی را فریاد می زنیم increment تابع
که بالاتر از مقدار بسته شده است 0 برای count قبل از اینکه فرصتی پیدا کند
بر اساس کلیک قبلی به‌روزرسانی می‌شود و تا زمانی که React دوباره رندر شود به همین شکل باقی می‌ماند.

بنابراین ممکن است فکر کنید که ما می توانیم این مشکل را حل کنیم اگر فقط بتوانیم a را راه اندازی کنیم
قبل از عملیات async دوباره رندر بگیرید، اما این کار برای ما نیز انجام نمی شود. این
مشکل این رویکرد این است که در حالی که increment دسترسی دارد count برای
این رندر به آن دسترسی نخواهد داشت count متغیر برای رندر بعدی
در واقع در رندر بعدی یک رندر کاملا متفاوت خواهیم داشت increment
تابعی که دسترسی به کاملا متفاوت دارد count متغیر پس ما خواهیم کرد
ما به طور موثر دو نسخه از همه متغیرهای خود داریم که ارائه می کنیم. ( زباله
مجموعه معمولاً کپی ها را پاک می کند و ما فقط باید نگران آن باشیم
اینجا و اکنون.) اما از آنجایی که count هنوز به روز نشده است که جدید است
کپی از increment ایجاد شده است، ارزش count هنوز هم هست 0 و در اینجا دلیل آن است
همین 0 وقتی برای بار دوم و همچنین بار اول روی دکمه کلیک می کنیم.

متوجه خواهید شد که اگر قبل از کلیک کردن منتظر بمانید تا مقدار شمارش به روز شود
دوباره دکمه، همه چیز خوب کار می کند، به این دلیل است که ما مدت زیادی منتظر ماندیم
برای اینکه رندر مجدد اتفاق بیفتد و یک رندر جدید کافی است increment یک تابع بود
ایجاد شده با آخرین مقدار برای count.

اما بدیهی است که این کمی گیج کننده و همچنین کمی مشکل ساز است. و همینطور
راه حل چیست به روز رسانی های ویژگی! چیزی که ما واقعا به آن نیاز داریم راهی است
مقدار قبلی را تعیین کنید count هنگامی که ما به روز رسانی خود را انجام می دهیم تا بتوانیم
آن را بر اساس مقدار شمارش قبلی تعیین کنید.

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

پس راه حل اینجاست:

function DelayedCounter() {
	const [count, setCount] = React.useState(0)
	const increment = async () => {
		await doSomethingAsync()
		setCount((previousCount) => previousCount + 1)
	}
	return button onClick={increment}>{count}button>
}

اینجا را امتحان کنید:

می توانید هر چند وقت یکبار که دوست دارید روی این کلیک کنید و به روز رسانی تعداد را مدیریت می کند
برای هر کلیک این کار می کند زیرا ما دیگر نگران دسترسی به یک مقدار نیستیم
که می تواند “بیات” باشد، اما در عوض به آخرین مقدار دسترسی داریم
متغیری که نیاز داریم بنابراین حتی اگر increment ویژگی ما در کار است
نسخه قدیمی تر count، ویژگی به روز رسانی ما جدیدترین است
نسخه کشور

باید اضافه کنم که اگر استفاده کنید مشکل مشابهی نخواهید داشت useReducer
زیرا این همیشه آخرین نسخه را دریافت می کند state (مثل
اولین استدلال برای کاهنده خود) بنابراین لازم نیست نگران وضعیت بیات باشید
ارزش ها اگر چه یک استثنا برای این امر در صورتی است که به‌روزرسانی وضعیت شما تنظیم شده باشد
توسط پایه ها یا برخی شرایط خارجی، در این صورت ممکن است به الف نیاز داشته باشید useRef برای کمک کردن
مطمئن شوید که جدیدترین نسخه از این پایه یا حالت خارجی را دارید. اما
موضوعی برای پست وبلاگ دیگری است…

امیدوارم این به توضیح چیستی/چرا/چگونه کمک کند useState اولیه کننده های تنبل و
dispatch به روز رسانی ویژگی ها اولیه سازهای تنبل برای بهبود عملکرد مفید هستند
مشکلات در برخی سناریوها، ارسال به‌روزرسانی‌های ویژگی به شما کمک می‌کند از مشکلات جلوگیری کنید
با مقادیر قدیمی

اگر این پست را دوست داشتید، ممکن است آن را نیز دوست داشته باشید
نحوه پیاده سازی useState با useReducer
و آیا باید ازState یا useReducer استفاده کنم.

موفق باشید!


Source link

نوشته های مشابه

دیدگاهتان را بنویسید

همچنین ببینید
بستن
دکمه بازگشت به بالا