راهنمای جامع React forwardRef، شامل هدف، پیادهسازی، موارد استفاده و بهترین شیوهها برای ساخت کامپوننتهای React بسیار قابل استفاده مجدد و قابل نگهداری.
React forwardRef: تسلط بر ارسال Ref برای کامپوننتهای قابل استفاده مجدد
در دنیای React، ساخت کامپوننتهای قابل استفاده مجدد و ترکیبپذیر از اهمیت بالایی برخوردار است. با این حال، گاهی اوقات شما نیاز دارید که از کامپوننت والد به گره DOM زیرین یک کامپوننت فرزند دسترسی پیدا کنید. اینجاست که React.forwardRef
به کمک میآید. این راهنمای جامع به بررسی جزئیات forwardRef
، توضیح هدف، پیادهسازی، موارد استفاده و بهترین شیوههای آن میپردازد.
ارسال Ref چیست؟
ارسال Ref (Ref forwarding) تکنیکی در React است که به یک کامپوننت والد اجازه میدهد به گره DOM یا نمونه کامپوننت React یک کامپوننت فرزند دسترسی پیدا کند. در اصل، این تکنیک یک ref که به یک کامپوننت ارسال شده را به یکی از فرزندانش "فوروارد" میکند. این امر به ویژه زمانی مفید است که نیاز به دستکاری مستقیم DOM یک کامپوننت فرزند دارید، مانند فوکوس کردن روی یک فیلد ورودی یا اندازهگیری ابعاد آن.
بدون forwardRef
، refها فقط میتوانند مستقیماً به عناصر DOM یا کامپوننتهای کلاسی متصل شوند. کامپوننتهای تابعی نمیتوانند مستقیماً ref دریافت کرده یا در معرض نمایش قرار دهند.
چرا از forwardRef
استفاده کنیم؟
سناریوهای متعددی استفاده از forwardRef
را ضروری میسازند:
- دستکاری DOM: زمانی که نیاز به تعامل مستقیم با DOM یک کامپوننت فرزند دارید. به عنوان مثال، تنظیم فوکوس روی یک فیلد ورودی، فعال کردن انیمیشنها، یا اندازهگیری عناصر.
- انتزاع (Abstraction): هنگام ایجاد کامپوننتهای UI قابل استفاده مجدد که نیاز دارند عناصر DOM خاصی را برای سفارشیسازی یا ادغام در سایر بخشهای برنامه در معرض نمایش قرار دهند.
- کامپوننتهای مرتبه بالاتر (HOCs): زمانی که یک کامپوننت را با یک HOC میپوشانید و نیاز دارید اطمینان حاصل کنید که refها به درستی به کامپوننت زیرین منتقل میشوند.
- کتابخانههای کامپوننت: هنگام ساخت کتابخانههای کامپوننت، ارسال ref به توسعهدهندگان این امکان را میدهد که به عناصر DOM زیرین کامپوننتهای شما دسترسی داشته و آنها را سفارشی کنند، که این امر انعطافپذیری بیشتری را فراهم میکند.
forwardRef
چگونه کار میکند
React.forwardRef
یک کامپوننت مرتبه بالاتر (HOC) است که یک تابع رندر را به عنوان آرگومان خود میپذیرد. این تابع رندر، props
و ref
را به عنوان آرگومان دریافت میکند. سپس تابع رندر یک عنصر React را برمیگرداند. آرگومان ref
همان ref است که از والد به کامپوننت ارسال شده است. سپس میتوانید این ref را به یک کامپوننت فرزند در داخل تابع رندر متصل کنید.
در اینجا خلاصهای از این فرآیند ارائه شده است:
- یک کامپوننت والد با استفاده از
useRef
یک ref ایجاد میکند. - کامپوننت والد ref را به عنوان یک prop به کامپوننت فرزند ارسال میکند.
- کامپوننت فرزند در
React.forwardRef
پیچیده میشود. - درون تابع رندر
forwardRef
، ref به یک عنصر DOM یا کامپوننت React دیگری متصل میشود. - اکنون کامپوننت والد میتواند از طریق ref به گره DOM یا نمونه کامپوننت دسترسی پیدا کند.
پیادهسازی forwardRef
: یک مثال عملی
بیایید forwardRef
را با یک مثال ساده نشان دهیم: یک کامپوننت ورودی سفارشی که به کامپوننت والد اجازه میدهد تا به صورت برنامهریزی شده روی فیلد ورودی فوکوس کند.
مثال: کامپوننت ورودی سفارشی با ارسال Ref
ابتدا، کامپوننت ورودی سفارشی را ایجاد کنیم:
import React, { forwardRef } from 'react';
const CustomInput = forwardRef((props, ref) => {
return (
<div>
<label htmlFor={props.id}>{props.label}</label>
<input type="text" id={props.id} ref={ref} {...props} />
</div>
);
});
CustomInput.displayName = "CustomInput"; // برای دیباگ بهتر توصیه میشود
export default CustomInput;
در این مثال:
- ما
forwardRef
را از 'react' ایمپورت میکنیم. - ما کامپوننت تابعی خود را با
forwardRef
میپوشانیم. - تابع
forwardRef
آرگومانهایprops
وref
را دریافت میکند. - ما
ref
را به عنصر<input>
متصل میکنیم. - ما
displayName
را برای دیباگ بهتر در React DevTools تنظیم میکنیم.
اکنون، بیایید ببینیم چگونه از این کامپوننت در یک کامپوننت والد استفاده کنیم:
import React, { useRef, useEffect } from 'react';
import CustomInput from './CustomInput';
const ParentComponent = () => {
const inputRef = useRef(null);
useEffect(() => {
// با ماونت شدن کامپوننت، روی فیلد ورودی فوکوس کن
if (inputRef.current) {
inputRef.current.focus();
}
}, []);
return (
<div>
<CustomInput label="Name:" id="name" ref={inputRef} placeholder="Enter your name" />
</div>
);
};
export default ParentComponent;
در این کامپوننت والد:
- ما با استفاده از
useRef
یک ref ایجاد میکنیم. - ما
inputRef
را به عنوان propref
به کامپوننتCustomInput
ارسال میکنیم. - در داخل هوک
useEffect
، ما با استفاده ازinputRef.current
به گره DOM زیرین دسترسی پیدا کرده و متدfocus()
را فراخوانی میکنیم.
هنگامی که ParentComponent
ماونت میشود، فیلد ورودی در کامپوننت CustomInput
به طور خودکار فوکوس میشود.
موارد استفاده از forwardRef
در اینجا برخی از موارد استفاده رایج که forwardRef
در آنها بسیار ارزشمند است، آورده شده است:
۱. فوکوس کردن روی فیلدهای ورودی
همانطور که در مثال بالا نشان داده شد، forwardRef
به شما امکان میدهد تا به صورت برنامهریزی شده روی فیلدهای ورودی فوکوس کنید، که برای اعتبارسنجی فرم، دسترسپذیری و بهبود تجربه کاربری مفید است. به عنوان مثال، پس از اینکه کاربر فرمی با خطا را ارسال کرد، میتوانید روی اولین فیلد ورودی دارای خطا فوکوس کنید تا کاربر را راهنمایی کنید.
۲. اندازهگیری ابعاد عناصر
میتوانید از forwardRef
برای دسترسی به گره DOM یک کامپوننت فرزند و اندازهگیری ابعاد آن (عرض، ارتفاع و غیره) استفاده کنید. این برای ایجاد طرحبندیهای واکنشگرا، اندازهگیری پویا و انیمیشنهای سفارشی مفید است. ممکن است لازم باشد ارتفاع یک ناحیه محتوای پویا را اندازهگیری کنید تا چیدمان سایر عناصر صفحه را تنظیم کنید.
۳. ادغام با کتابخانههای شخص ثالث
بسیاری از کتابخانههای شخص ثالث برای مقداردهی اولیه یا پیکربندی به دسترسی مستقیم به گرههای DOM نیاز دارند. forwardRef
به شما امکان میدهد این کتابخانهها را به طور یکپارچه با کامپوننتهای React خود ادغام کنید. تصور کنید از یک کتابخانه نمودارسازی استفاده میکنید که برای رندر کردن نمودار به یک عنصر DOM به عنوان هدف نیاز دارد. forwardRef
شما را قادر میسازد تا آن عنصر DOM را به کتابخانه ارائه دهید.
۴. ساخت کامپوننتهای قابل دسترس
دسترسپذیری اغلب به دستکاری مستقیم ویژگیهای DOM یا مدیریت فوکوس نیاز دارد. forwardRef
میتواند برای ایجاد کامپوننتهای قابل دسترس که با استانداردهای دسترسپذیری مطابقت دارند، استفاده شود. به عنوان مثال، ممکن است لازم باشد ویژگی aria-describedby
را روی یک فیلد ورودی تنظیم کنید تا آن را با یک پیام خطا مرتبط کنید. این کار به دسترسی مستقیم به گره DOM فیلد ورودی نیاز دارد.
۵. کامپوننتهای مرتبه بالاتر (HOCs)
هنگام ایجاد HOCها، مهم است که اطمینان حاصل کنید refها به درستی به کامپوننت پیچیده شده منتقل میشوند. forwardRef
به شما در دستیابی به این هدف کمک میکند. فرض کنید یک HOC دارید که به یک کامپوننت استایل اضافه میکند. استفاده از forwardRef
تضمین میکند که هر ref که به کامپوننت استایلدهی شده ارسال میشود، به کامپوننت زیرین فوروارد میشود.
بهترین شیوهها برای استفاده از forwardRef
برای اطمینان از استفاده مؤثر از forwardRef
، این بهترین شیوهها را در نظر بگیرید:
۱. استفاده از displayName
برای دیباگ کردن
همیشه ویژگی displayName
را روی کامپوننتهای forwardRef
خود تنظیم کنید. این کار شناسایی آنها را در React DevTools آسانتر میکند. به عنوان مثال:
CustomInput.displayName = "CustomInput";
۲. به عملکرد توجه داشته باشید
در حالی که forwardRef
ابزار قدرتمندی است، در صورت استفاده بیش از حد میتواند بر عملکرد تأثیر بگذارد. از دستکاری غیرضروری DOM خودداری کرده و منطق رندر خود را بهینه کنید. برنامه خود را پروفایل کنید تا هرگونه تنگنای عملکردی مرتبط با ارسال ref را شناسایی کنید.
۳. از Refها با احتیاط استفاده کنید
از refها به عنوان جایگزینی برای جریان داده React استفاده نکنید. Refها باید به ندرت و فقط در صورت لزوم برای دستکاری DOM یا ادغام با کتابخانههای شخص ثالث استفاده شوند. برای مدیریت دادهها و رفتار کامپوننت به props و state تکیه کنید.
۴. کامپوننتهای خود را مستندسازی کنید
به وضوح مستند کنید که چه زمانی و چرا از forwardRef
در کامپوننتهای خود استفاده میکنید. این به سایر توسعهدهندگان کمک میکند تا کد شما را درک کرده و از کامپوننتهای شما به درستی استفاده کنند. مثالهایی از نحوه استفاده از کامپوننت و هدف از ref فوروارد شده را شامل کنید.
۵. جایگزینها را در نظر بگیرید
قبل از استفاده از forwardRef
، بررسی کنید که آیا راهحلهای جایگزینی وجود دارد که ممکن است مناسبتر باشند. به عنوان مثال، ممکن است بتوانید با استفاده از props و state به جای دستکاری مستقیم DOM به رفتار مورد نظر دست یابید. قبل از توسل به forwardRef
گزینههای دیگر را بررسی کنید.
جایگزینهای forwardRef
در حالی که forwardRef
اغلب بهترین راهحل برای ارسال refها است، رویکردهای جایگزینی وجود دارد که ممکن است در شرایط خاصی در نظر بگیرید:
۱. Callback Refs
Callback refs روش انعطافپذیرتری برای دسترسی به گرههای DOM فراهم میکنند. به جای ارسال یک prop ref
، شما تابعی را ارسال میکنید که گره DOM را به عنوان آرگومان دریافت میکند. این به شما امکان میدهد تا هنگام متصل یا جدا شدن گره DOM، منطق سفارشی را اجرا کنید. با این حال، callback refs میتوانند پرمخاطبتر و خوانایی کمتری نسبت به forwardRef
داشته باشند.
const MyComponent = () => {
let inputElement = null;
const setInputElement = (element) => {
inputElement = element;
};
useEffect(() => {
if (inputElement) {
inputElement.focus();
}
}, []);
return <input type="text" ref={setInputElement} />;
};
۲. ترکیب (Composition)
در برخی موارد، میتوانید با ترکیب کامپوننتها به جای استفاده از forwardRef
به رفتار مورد نظر دست یابید. این شامل شکستن یک کامپوننت پیچیده به کامپوننتهای کوچکتر و قابل مدیریتتر و انتقال دادهها و رفتار بین آنها با استفاده از props است. ترکیب میتواند به کدی قابل نگهداریتر و قابل آزمایشتر منجر شود، اما ممکن است برای همه سناریوها مناسب نباشد.
۳. Render Props
Render props به شما امکان میدهند کد را بین کامپوننتهای React با استفاده از یک prop که مقدار آن یک تابع است، به اشتراک بگذارید. میتوانید از render props برای در معرض نمایش قرار دادن گرههای DOM یا نمونههای کامپوننت به کامپوننت والد استفاده کنید. با این حال، render props میتوانند کد شما را پیچیدهتر و خواندن آن را دشوارتر کنند، به خصوص هنگام کار با چندین render prop.
اشتباهات رایج که باید از آنها اجتناب کرد
هنگام کار با forwardRef
، مهم است که از این اشتباهات رایج اجتناب کنید:
۱. فراموش کردن تنظیم displayName
همانطور که قبلاً ذکر شد، فراموش کردن تنظیم ویژگی displayName
میتواند دیباگ کردن را دشوار کند. همیشه displayName
را برای کامپوننتهای forwardRef
خود تنظیم کنید.
۲. استفاده بیش از حد از Refها
در برابر وسوسه استفاده از refها برای همه چیز مقاومت کنید. Refها باید به ندرت و فقط در صورت لزوم برای دستکاری DOM یا ادغام با کتابخانههای شخص ثالث استفاده شوند. برای مدیریت دادهها و رفتار کامپوننت به props و state تکیه کنید.
۳. دستکاری مستقیم DOM بدون دلیل موجه
دستکاری مستقیم DOM میتواند نگهداری و آزمایش کد شما را دشوارتر کند. فقط در صورت لزوم مطلق DOM را دستکاری کنید و از بهروزرسانیهای غیرضروری DOM خودداری کنید.
۴. مدیریت نکردن Refهای null
همیشه قبل از دسترسی به گره DOM یا نمونه کامپوننت زیرین، بررسی کنید که آیا ref null است یا خیر. این از بروز خطا هنگامیکه کامپوننت هنوز ماونت نشده یا آنماونت شده است، جلوگیری میکند.
if (inputRef.current) {
inputRef.current.focus();
}
۵. ایجاد وابستگیهای دَوَرانی
هنگام استفاده از forwardRef
در ترکیب با تکنیکهای دیگر مانند HOCها یا render props مراقب باشید. از ایجاد وابستگیهای دورانی بین کامپوننتها خودداری کنید، زیرا این میتواند به مشکلات عملکردی یا رفتار غیرمنتظره منجر شود.
مثالهایی از سراسر جهان
اصول React و forwardRef
جهانی هستند، اما در نظر بگیرید که چگونه توسعهدهندگان از مناطق مختلف ممکن است استفاده از آن را تطبیق دهند:
- محلیسازی و بینالمللیسازی (i18n): توسعهدهندگانی که برنامههای چندزبانه در اروپا یا آسیا میسازند ممکن است از
forwardRef
برای اندازهگیری اندازه عناصر متنی محلیسازی شده استفاده کنند تا طرحبندیها را به صورت پویا برای زبانهای مختلف تنظیم کنند و اطمینان حاصل کنند که متن از کانتینرها سرریز نمیکند. به عنوان مثال، کلمات آلمانی معمولاً طولانیتر از کلمات انگلیسی هستند و نیاز به تنظیمات دارند. - چیدمانهای راست-به-چپ (RTL): در خاورمیانه و بخشهایی از آسیا، برنامهها اغلب نیاز به پشتیبانی از چیدمانهای RTL دارند.
forwardRef
میتواند برای تنظیم برنامهریزی شده موقعیت عناصر بر اساس جهت چیدمان فعلی استفاده شود. - دسترسپذیری برای کاربران متنوع: در سطح جهانی، دسترسپذیری یک نگرانی رو به رشد است. توسعهدهندگان ممکن است از
forwardRef
برای بهبود دسترسپذیری برای کاربران دارای معلولیت استفاده کنند، مانند فوکوس برنامهریزی شده روی عناصر برای صفحهخوانها یا تنظیم ترتیب تب فیلدهای فرم. - ادغام با APIهای منطقهای: توسعهدهندگانی که با APIهای محلی (مانند درگاههای پرداخت، خدمات نقشه) ادغام میشوند، ممکن است از
forwardRef
برای دسترسی به عناصر DOM مورد نیاز آن APIها استفاده کنند تا از سازگاری و ادغام یکپارچه اطمینان حاصل کنند.
نتیجهگیری
React.forwardRef
ابزاری قدرتمند برای ایجاد کامپوننتهای React قابل استفاده مجدد و ترکیبپذیر است. با اجازه دادن به کامپوننتهای والد برای دسترسی به گرههای DOM یا نمونههای کامپوننت فرزندانشان، forwardRef
طیف گستردهای از موارد استفاده را، از دستکاری DOM گرفته تا ادغام با کتابخانههای شخص ثالث، امکانپذیر میسازد. با پیروی از بهترین شیوههای ذکر شده در این راهنما، میتوانید از forwardRef
به طور مؤثر استفاده کرده و از اشتباهات رایج جلوگیری کنید. به یاد داشته باشید که از refها با احتیاط استفاده کنید، کامپوننتهای خود را به وضوح مستندسازی کنید و در صورت لزوم راهحلهای جایگزین را در نظر بگیرید. با درک کامل از forwardRef
، میتوانید برنامههای React قویتر، انعطافپذیرتر و قابل نگهداریتری بسازید.