useState
و useReducer
می تواند باعث شود که م componentلفه شما هر بار که به توابع به روزرسانی فراخوانی می شود ، دوباره ارائه شود. در این مقاله ، نحوه استفاده از useRef()
قلاب برای پیگیری متغیرها بدون ایجاد رندر مجدد ، و نحوه اجرای رندر مجدد کامپوننت های React.
در کامپوننت های React ، مواردی وجود دارد که تغییرات مکرر باید بدون اعمال مجدد اجرای مجدد م componentلفه پیگیری شود. همچنین می تواند نیاز به ارائه مجدد م theثر مثر باشد. در حالی که useState
و useReducer
قلاب ها React API برای مدیریت وضعیت محلی در یک م componentلفه React هستند ، همچنین ممکن است هزینه فراوانی داشته باشند که باعث می شود اغلب م componentلفه برای ارائه مجدد برای هر تماس ایجاد شده در عملکردهای بروزرسانی ، ارائه شود.
در این مقاله ، دلیل آن را توضیح می دهم useState
برای ردیابی برخی از ایالات کارآمد نیست ، نشان می دهد که چگونه useState
رندر مجدد بیش از حد از یک م componentلفه ایجاد می کند ، چگونه مقادیری که در یک متغیر ذخیره می شوند در یک م componentلفه باقی نمی مانند و آخرین ، نه مهمترین ، چگونگی useRef
بدون ایجاد رندر مجدد از م componentلفه می توان از متغیرها پیگیری کرد. و یک راه حل در مورد نحوه اجرای رندر مجدد بدون تأثیر بر عملکرد یک م solutionلفه ارائه دهید.
بعد از تکامل م componentsلفه های عملکردی ، م componentsلفه های عملکردی توانایی داشتن حالت محلی را دارند که باعث می شود رندر مجدد م componentلفه به محض بروزرسانی در هر حالت محلی آنها انجام شود.
function Card (props) {
const [toggled, setToggled] = useState(false);
const handleToggleBody = () => {
setToggled(!toggled)
}
return (<section className="card">
<h3 className="card__title" onMouseMove={handleToggleBody}>
{props.title}
</h3>
{toggled && <article className="card__body">
{props.body}
</article>}
</section>)
}
// Consumed as:
<Card name="something" body="very very interesting" />
در جز above بالا ، کارت با استفاده از a ارائه می شود section
عنصر داشتن فرزند h3
با یک card__title
کلاس که عنوان کارت را دارد ، بدنه کارت در یک برچسب مقاله با بدنه از ارائه می شود card__body
. ما به title
و body
از غرفه ها برای تنظیم محتوای عنوان و بدنه کارت ، در حالی که بدنه فقط هنگامی که هدر روی آن قرار دارد ضامن می شود.

ارائه مجدد کامپوننت با useState
رندر اولیه یک م componentلفه زمانی انجام می شود که یک م componentلفه دارای مقادیر حالت بکر و رقیق نشده باشد ، دقیقاً مانند م componentلفه Card ، رندر اولیه آن زمانی است که رویداد تغییر ماوس هنوز فعال نشده است. رندر مجدد یک م componentلفه در م componentلفه ای انجام می شود که یکی از حالت های محلی یا برنامه های آن به روز شده باشد ، این باعث می شود که ملفه با فراخوانی روش رندر خود ، جدیدترین عناصر را براساس به روزرسانی حالت نمایش دهد.
در Card
جز component ، mousemove
مسئول کنترل رویدادها handleToggleBody
تابع برای به روزرسانی حالت نفی مقدار قبلی حالت ضامن.
این سناریو را می توانیم در handleToggleBody
عملکرد فراخوانی setToggled
عملکرد به روز رسانی حالت. این امر باعث می شود تا هر بار که رویداد تحریک می شود ، عملکرد فراخوانی شود.
ذخیره مقادیر حالت در یک متغیر
یک راه حل برای رندر مجدد مکرر استفاده از a است متغیر محلی در داخل م componentلفه ، حالت ضامنی را دارد که می تواند برای جلوگیری از رندر مجدد مکرر نیز به روز شود – که فقط درصورت بروزرسانی در حالت های محلی یا برنامه های م aلفه انجام می شود.
function Card (props) {
let toggled = false;
const handleToggleBody = () => {
toggled = !toggled;
console.log(toggled);
}
return (<section className="card">
<section className="cardTitle" onMouseMove={handleToggleBody}>
{title}
</section>
{toggled && <article className="cardBody">
{body}
</article>}
</section>)
}
<Card name="something" body="very very interesting" />
این یک رفتار غیرمنتظره است که در آن مقدار به روز می شود اما م componentلفه دوباره ارائه نمی شود زیرا هیچ حالت داخلی یا برآمده ای برای ایجاد رندر مجدد م componentلفه تغییر نکرده است.

متغیرهای محلی در کل ارائه ادامه ندارند
بیایید مراحل رندر اولیه تا رندر مجدد یک م componentلفه React را در نظر بگیریم.
- در ابتدا ، م componentلفه تمام متغیرها را به مقادیر پیش فرض مقداردهی می کند ، همچنین تمام حالت را ذخیره می کند و به یک فروشگاه منحصر به فرد که توسط الگوریتم React تعریف شده است ، ارسال می کند.
- وقتی یک به روزرسانی جدید از طریق یک به روزرسانی به لوازم یا حالت آن برای م updateلفه در دسترس باشد ، React مقدار قدیمی را برای حالت ها می کشد و از فروشگاه خودداری می کند و مجدداً مقدار را به مقدار قدیمی تنظیم می کند و همچنین یک به روزرسانی را برای حالت ها اعمال می کند و رد می کند که به روز کنید
- سپس این تابع را برای م componentلفه اجرا می کند تا م componentلفه را با وضعیت ها و Ref های به روز شده ارائه دهد. این رندر مجدد همچنین متغیرها را مجدداً مقداردهی می کند تا مقادیر اولیه خود را همانطور که در م componentلفه تعریف شده است نگه دارد زیرا ردیابی نمی شود.
- سپس م componentلفه دوباره ارائه می شود.
در زیر مثالی آورده شده است که می تواند این را نشان دهد:
function Card (props) {
let toggled = false;
const handleToggleBody = () => {
toggled = true;
console.log(toggled);
};
useEffect(() => {
console.log(“Component rendered, the value of toggled is:“, toggled);
}, [props.title]);
return (
<section className=“card”>
<h3 className=“card__title” onMouseMove={handleToggleBody}>
{props.title}
</h3>
{toggled && <article className=“card__body”>{props.body}</article>}
</section>
);
}
// Renders the application
function App () {
const [cardDetails, setCardDetails] = useState({
title: “Something”,
body: “uniquely done”,
});
useEffect(() => {
setTimeout(() => {
setCardDetails({
title: “We”,
body: “have updated something nice”,
});
}, 5000); // Force an update after 5s
}, []);
return (
<div>
<Card title={cardDetails.title} body={cardDetails.body} />
</div>
);
}
در کد بالا ، Card
جز component به عنوان یک کودک در ارائه می شود App
جزء. App
م componentلفه متکی به یک شی state داخلی به نام است cardDetails
برای ذخیره جزئیات کارت. همچنین ، این م makesلفه به روزرسانی می شود cardDetails
بعد از 5 ثانیه رندر اولیه برای مجبور کردن یک رندر مجدد از حالت Card
لیست م componentلفه ها
Card
رفتاری جزئی دارد به جای تغییر حالت ضامن ، روی آن تنظیم شده است true
وقتی یک نشانگر ماوس روی عنوان کارت قرار می گیرد. همچنین یک useEffect
از قلاب برای ردیابی مقدار استفاده می شود toggled
متغیر پس از ارائه مجدد.

نتیجه پس از اجرای این کد و قرار دادن ماوس بر روی عنوان ، متغیر را به روز می کند اما باعث رندر مجدد نمی شود ، در عین حال ، رندر مجدد توسط م parentلفه والد تحریک می شود که متغیر را مجدداً به حالت اولیه تبدیل می کند false
همانطور که در جز تعریف شده است. جالب هست!
در باره useRef()
قلاب
دسترسی به عناصر DOM با استفاده از vanilla JavaScript a ، اصلی JavaScript در مرورگر است div
عنصر با کلاس "title"
با استفاده از:
<div class="title">
This is a title of a div
</div>
<script>
const titleDiv = document.querySelector("div.title")
</script>
از ارجاع به این عنصر می توان برای انجام کارهای جالب مانند تغییر محتوای متن استفاده کرد titleDiv.textContent = "this is a newer title"
یا تغییر نام کلاس titleDiv.classList = "This is the class"
و عملیات بسیار بیشتر
اضافه کار ، کتابخانه های دستکاری DOM مانند jQuery این فرآیند را با یک تماس عملکردی با استفاده از $
امضاء کردن. دریافت همان عنصر با استفاده از jQuery از طریق امکان پذیر است const el = ("div.title")
، همچنین محتوای متن را می توان از طریق API jQuery به روز کرد: el.text("New text for the title div")
.
Refs در واکنش از طریق useRef
قلاب
ReactJS که یک کتابخانه پیشرو مدرن است با ارائه یک API Ref برای دسترسی به عنصر آن و حتی یک قدم جلوتر از useRef
قلاب برای یک جز functional کاربردی.
import React, {useRef, useEffect} from "react";
export default function (props) {
// Initialized a hook to hold the reference to the title div.
const titleRef = useRef();
useEffect(function () {
setTimeout(() => {
titleRef.current.textContent = "Updated Text"
}, 2000); // Update the content of the element after 2seconds
}, []);
return <div className="container">
{/** The reference to the element happens here **/ }
<div className="title" ref={titleRef}>Original title</div>
</div>
}

همانطور که در بالا مشاهده شد ، پس از 2 ثانیه ارائه اولیه م componentلفه ، محتوای متن برای div
عنصر با className عنوان به “متن به روز شده” تغییر می کند.
چگونه ارزش ها ذخیره می شوند useRef
یک متغیر Ref در React یک شی قابل تغییر است ، اما مقدار آن توسط React در رندرهای مجدد باقی می ماند. یک شی ref ref یک خاصیت واحد به نام دارد current
ساخت refs ساختاری شبیه به { current: ReactElementReference }
.
تصميم گيري توسط تيم React براي پايداري و قابليت تغيير پذيرش ، تصميمي عالمانه است. به عنوان مثال ، در هنگام رندر مجدد یک ملفه ، ممکن است عنصر DOM در طی فرآیند به روز شود ، پس لازم است که رفرنس به عنصر DOM نیز به روز شود و اگر به روز نشده باشد ، مرجع باید حفظ شود. این کمک می کند تا از ناسازگاری در ارائه نهایی جلوگیری شود.
به طور صریح ارزش A را به روز کنید useRef
متغیر
به روزرسانی به useRef
متغیر ، مقدار جدید را می توان به .current
از یک متغیر ref. این کار باید با احتیاط انجام شود ، هنگامی که یک متغیر ref به یک عنصر DOM ارجاع می دهد که می تواند باعث برخی از رفتارهای غیر منتظره شود ، جدا از این ، به روزرسانی یک متغیر ref است بی خطر.
function User() {
const name = useRef("Aleem");
useEffect(() => {
setTimeout(() => {
name.current = "Isiaka";
console.log(name);
}, 5000);
});
return <div>{name.current}</div>;
}
ذخیره ارزش ها در useRef
یک روش منحصر به فرد برای پیاده سازی useRef
قلاب استفاده از آن برای ذخیره مقادیر به جای منابع DOM است. این مقادیر یا می توانند حالتی باشند که نیازی به تغییر زیاد نداشته باشد و یا حالتی است که باید هرچه بیشتر تغییر کند اما نباید باعث بازسازی کامل ملفه شود.
برگرداندن مثال کارت ، به جای ذخیره مقادیر به عنوان حالت یا یک متغیر ، به جای آن از ref استفاده می شود.
function Card (props) {
let toggled = useRef(false);
const handleToggleBody = () => {
toggled.current = !toggled.current;
}
return (
<section className=“card”>
<h3 className=“card__title” onMouseMove={handleToggleBody}>
{props.title}
</h3>
{toggled && <article className=“card__body”>{props.body}</article>}
</section>
);
</section>)
}
این کد از نظر داخلی نتیجه مطلوبی می دهد اما از نظر بصری نتیجه نمی دهد. مقدار حالت ضامن همچنان پابرجا است اما هنگام انجام به روزرسانی ، هیچ رندر مجددی انجام نمی شود ، زیرا انتظار می رود ref ها مقادیر یکسانی را در طول چرخه حیات یک م holdلفه حفظ کنند ، React انتظار ندارد که تغییر کنند.
رندر کم عمق و عمیق
در React ، دو مکانیزم ارائه وجود دارد ، کم عمق و عمیق تفسیر. رندر کم عمق فقط بر روی م componentلفه تأثیر می گذارد و بر کودکان تأثیر نمی گذارد ، در حالی که رندر عمیق روی م componentلفه و همه فرزندان آن تأثیر می گذارد.
هنگامی که یک به روزرسانی به یک ref تبدیل می شود ، از مکانیزم کم عمق رندر برای رندر مجدد م componentلفه استفاده می شود.
function UserAvatar (props) {
return <img src={props.src} />
}
function Username (props) {
return <span>{props.name}</span>
}
function User () {
const user = useRef({
name: "Aleem Isiaka",
avatarURL: "https://icotar.com/avatar/jake.png?bg=e91e63",
})
console.log("Original Name", user.current.name);
console.log("Original Avatar URL", user.current.avatarURL);
useEffect(() => {
setTimeout(() => {
user.current = {
name: "Isiaka Aleem",
avatarURL: "https://icotar.com/avatar/craig.png?s=50", // a new image
};
},5000)
})
// Both children won't be re-rendered due to shallow rendering mechanism
// implemented for useRef
return (<div>
<Username name={user.name} />
<UserAvatar src={user.avatarURL} />
</div>);
}
در مثال بالا ، اطلاعات کاربر در یک Ref ذخیره می شود که پس از 5 ثانیه به روز می شود ، کاربر دارای دو فرزند است ، نام کاربری برای نمایش نام کاربر و UserAvatar
برای نمایش تصویر آواتار کاربر.
بعد از به روزرسانی ، مقدار useRef
به روز شده است اما کودکان در حال به روزرسانی رابط کاربری خود نیستند زیرا دوباره ارائه نمی شوند. این بازپرداخت کم عمق است ، و همان چیزی است که برای استفاده از قلاب Ref استفاده می شود.

رندرینگ عمیق هنگامی استفاده می شود که به روزرسانی در یک حالت با استفاده از useState
قلاب یا به روزرسانی غرفه های م componentلفه.
function UserAvatar (props) {
return <img src={props.src} />
}
function Username (props) {
return <span>{props.name}</span>
}
function User () {
const [user, setUser] = useState({
name: "Aleem Isiaka",
avatarURL: "https://icotar.com/avatar/jake.png?bg=e91e63",
});
useEffect(() => {
setTimeout(() => {
setUser({
name: "Isiaka Aleem",
avatarURL: "https://icotar.com/avatar/craig.png?s=50", // a new image
});
},5000);
})
// Both children are re-rendered due to deep rendering mechanism
// implemented for useState hook
return (<div>
<Username name={user.name} />
<UserAvatar src={user.avatarURL} />
</div>);
}

برخلاف نتیجه ای که وقتی تجربه شده است useRef
مورد استفاده قرار می گیرد ، در این حالت ، کودکان آخرین مقدار را دریافت می کنند و دوباره ارائه می شوند و باعث می شود رابط کاربر آنها اثرات مطلوبی داشته باشد.
اجبار یک رندر عمیق برای useRef
به روز رسانی
برای دستیابی به یک رندر عمیق ، هنگامی که یک به روزرسانی برای refs انجام می شود ، مکانیزم ارائه رندر عمیق useState
قلاب می تواند باشد تا اندازه ای اجرا شده
function UserAvatar (props) {
return <img src={props.src} />
}
function Username (props) {
return <span>{props.name}</span>
}
function User () {
const user = useRef({
name: "Aleem Isiaka",
avatarURL: "https://icotar.com/avatar/jake.png?bg=e91e63",
})
const [, setForceUpdate] = useState(Date.now());
useEffect(() => {
setTimeout(() => {
user.current = {
name: "Isiaka Aleem",
avatarURL: "https://icotar.com/avatar/craig.png?s=50", // a new image
};
setForceUpdate();
},5000)
})
return (<div>
<Username name={user.name} />
<UserAvatar src={user.avatarURL} />
</div>);
}

در بهبود فوق به User
کامپوننت ، یک حالت معرفی می شود اما مقدار آن نادیده گرفته می شود زیرا نیازی به آن نیست ، در حالی که تابع بروزرسانی برای اجرای رندر مجدد م theلفه نامگذاری شده است setForceUpdate
برای حفظ کنوانسیون نامگذاری برای useState
قلاب. این م asلفه مطابق انتظار رفتار می کند و پس از به روزرسانی ref ، کودکان را دوباره ارائه می دهد.
این می تواند سوالاتی از جمله:
“آیا این یک ضد الگو نیست؟”
یا
“آیا این کار همان مشکل اولیه نیست بلکه متفاوت است؟”
مطمئنا ، این یک ضد الگو است ، زیرا ما از انعطاف پذیری استفاده می کنیم useRef
قلاب برای ذخیره ایالات محلی ، و هنوز هم تماس بگیرید useState
قلاب برای اطمینان از اینکه کودکان آخرین مقدار را دریافت می کنند useRef
مقدار جریان متغیر که با هر دو می توان به دست آورد useState
.
بله ، این در حال انجام است تقریبا همان مورد اولیه اما متفاوت است. setForceUpdate
تابع یک رندر مجدد عمیق انجام می دهد اما هیچ حالتی را که بر روی عنصر م componentلفه تأثیر بگذارد به روز نمی کند ، که آن را در رندر رندر ثابت نگه دارد.
نتیجه
به روزرسانی مکرر حالت در یک م stateلفه React با استفاده از useState
قلاب می تواند اثرات نامطلوب ایجاد کند. ما همچنین دیده ایم در حالی که متغیرها می توانند گزینه ای برای رفتن باشند. آنها مانند بازپرداخت یک م componentلفه همچنان ادامه ندارند.
Refs in React برای ذخیره مرجع به یک عنصر React استفاده می شود و مقادیر آنها در رندر مجدد باقی می ماند. Ref ها اشیا mut قابل تغییر هستند ، از این رو می توانند به طور صریح به روز شوند و می توانند مقادیر دیگری به جز ارجاع به عنصر React را در خود نگه دارند.
ذخیره مقادیر در ref ها مشکل رندر مکرر را برطرف می کند اما چالش جدیدی برای عدم به روزرسانی ملفه پس از تغییر مقدار ref به وجود آمده است که با معرفی setForceUpdate
عملکرد به روز رسانی حالت.
به طور کلی ، اجراهای اینجا:
- ما می توانیم مقادیر را در ref ها ذخیره کنیم و آنها را به روز کنیم ، که از کارآیی بیشتری برخوردار است
useState
که می تواند گران باشد وقتی که مقادیر باید در یک ثانیه چندین بار به روز شوند. - ما می توانیم React را مجبور به رندر مجدد یک م componentلفه کنیم ، حتی اگر نیازی به بروزرسانی نباشد با استفاده از یک مرجع غیر مرجع
useState
عملکرد به روزرسانی - ما می توانیم 1 و 2 را ترکیب کنیم تا یک جز ever با عملکرد بالا و همیشه در حال تغییر داشته باشیم.
منابع
