قدرت createRef در React را برای دسترسی مستقیم به DOM و تعامل با کامپوننتها آزاد کنید. این راهنما شامل مثالهای کاربردی و بهترین شیوهها برای توسعهدهندگان در سراسر جهان است.
تسلط بر createRef در React: راهنمای جامع برای توسعه مدرن
در دنیای پویای توسعه فرانتاند، React به عنوان یک کتابخانه جاوا اسکریپت قدرتمند و همهکاره برای ساخت رابطهای کاربری برجسته است. یکی از ویژگیهای کلیدی که به توسعهدهندگان React اجازه میدهد مستقیماً با مدل شیء سند (DOM) تعامل داشته باشند و رفتار کامپوننت را مدیریت کنند، API createRef
است. این راهنما به پیچیدگیهای createRef
میپردازد و درک جامعی از کاربرد، مزایا و بهترین شیوههای آن را برای توسعهدهندگان در سراسر جهان ارائه میدهد.
درک رفها (Refs) در React
قبل از پرداختن به createRef
، درک مفهوم رفها در React ضروری است. یک رف (ref) راهی برای دسترسی به گرههای DOM یا عناصر React ایجاد شده در متد رندر فراهم میکند. این دسترسی به شما امکان میدهد عملیاتی مانند فوکوس کردن روی یک فیلد ورودی، فعال کردن انیمیشنها یا اندازهگیری ابعاد یک عنصر را انجام دهید.
برخلاف دستکاری سنتی DOM در جاوا اسکریپت، رفها در React راهی کنترلشده و کارآمد برای تعامل با DOM فراهم میکنند. DOM مجازی React بسیاری از پیچیدگیهای دستکاری مستقیم DOM را پنهان میکند، اما رفها پلی را در مواقعی که دسترسی مستقیم ضروری است، ارائه میدهند.
معرفی createRef
createRef
تابعی است که توسط React ارائه شده و یک شیء رف (ref object) ایجاد میکند. این شیء رف دارای یک ویژگی current
است که گره DOM یا نمونه کامپوننت React را که رف به آن متصل شده، نگهداری میکند. API createRef
به عنوان بخشی از React 16.3 معرفی شد و روش توصیهشده برای ایجاد رفها در کامپوننتهای کلاسی است. برای کامپوننتهای تابعی، useRef
(یک هوک React) عملکرد مشابهی را ارائه میدهد.
ایجاد یک شیء رف
برای ایجاد یک شیء رف، کافی است تابع createRef()
را فراخوانی کنید:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return (
);
}
}
در این مثال، this.myRef
یک شیء رف است که به ویژگی ref
عنصر ورودی اختصاص داده شده است. ویژگی current
از this.myRef
پس از mount شدن کامپوننت، مرجعی به عنصر ورودی را در خود نگه میدارد.
دسترسی به گره DOM
پس از اینکه کامپوننت mount شد، میتوانید از طریق ویژگی current
شیء رف به گره DOM دسترسی پیدا کنید:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.focusInput = this.focusInput.bind(this);
}
componentDidMount() {
this.focusInput();
}
focusInput() {
this.myRef.current.focus();
}
render() {
return (
);
}
}
در این مثال، متد focusInput
از this.myRef.current
برای دسترسی به عنصر ورودی و فراخوانی متد focus()
آن استفاده میکند. این کار باعث میشود فیلد ورودی به طور خودکار هنگام mount شدن کامپوننت فوکوس شود.
موارد استفاده از createRef
createRef
در سناریوهای مختلفی که نیاز به دستکاری مستقیم DOM یا دسترسی به نمونههای کامپوننت وجود دارد، ارزشمند است. در اینجا برخی از موارد استفاده رایج آورده شده است:
- فوکوس کردن روی ورودیهای متنی: همانطور که در مثال قبلی نشان داده شد،
createRef
معمولاً برای فوکوس کردن روی ورودیهای متنی به صورت برنامهنویسی استفاده میشود. این کار برای بهبود تجربه کاربری با فوکوس خودکار روی اولین فیلد ورودی در یک فرم یا فوکوس روی یک فیلد ورودی پس از یک اقدام خاص مفید است. - مدیریت پخش رسانه: از رفها میتوان برای کنترل عناصر رسانهای مانند
<video>
یا<audio>
استفاده کرد. شما میتوانید از رفها برای پخش، توقف یا تنظیم صدای عناصر رسانهای استفاده کنید. برای مثال:import React from 'react'; class VideoPlayer extends React.Component { constructor(props) { super(props); this.videoRef = React.createRef(); this.playVideo = this.playVideo.bind(this); } playVideo() { this.videoRef.current.play(); } render() { return (
- فعالسازی انیمیشنها: از رفها میتوان برای دسترسی به عناصر DOM و فعالسازی انیمیشنها با استفاده از جاوا اسکریپت یا CSS استفاده کرد. این به شما امکان میدهد انیمیشنهای پیچیده و تعاملی ایجاد کنید که به اقدامات کاربر پاسخ میدهند.
import React from 'react'; class AnimatedBox extends React.Component { constructor(props) { super(props); this.boxRef = React.createRef(); this.animate = this.animate.bind(this); } animate() { const box = this.boxRef.current; box.classList.add('animate'); } render() { return (
در این مثال، کلیک روی دکمه، کلاس
animate
را به عنصر جعبه اضافه میکند و باعث فعال شدن یک انیمیشن CSS میشود. - اندازهگیری ابعاد و موقعیت عنصر: رفها برای به دست آوردن اندازه و موقعیت عناصر DOM مفید هستند. این اطلاعات میتواند برای محاسبات چیدمان، استایلدهی پویا یا ایجاد عناصر تعاملی استفاده شود.
import React from 'react'; class SizeReporter extends React.Component { constructor(props) { super(props); this.elementRef = React.createRef(); this.state = { width: 0, height: 0 }; this.reportSize = this.reportSize.bind(this); } componentDidMount() { this.reportSize(); } reportSize() { const element = this.elementRef.current; this.setState({ width: element.offsetWidth, height: element.offsetHeight }); } render() { return (
Width: {this.state.width}px, Height: {this.state.height}px
این کامپوننت عرض و ارتفاع div را پس از mount شدن گزارش میدهد.
- یکپارچهسازی با کتابخانههای شخص ثالث: رفها اغلب برای یکپارچهسازی کامپوننتهای React با کتابخانههای شخص ثالث که نیاز به دسترسی مستقیم به DOM دارند، استفاده میشوند. برای مثال، ممکن است از یک رف برای دسترسی به یک عنصر DOM و مقداردهی اولیه یک پلاگین jQuery روی آن استفاده کنید.
import React from 'react'; import $ from 'jquery'; class MyComponent extends React.Component { constructor(props) { super(props); this.elementRef = React.createRef(); } componentDidMount() { $(this.elementRef.current).plugin(); // Initialize jQuery plugin } render() { return ; } }
مقایسه createRef
با رفهای بازگشتی (Callback Refs)
قبل از معرفی createRef
، رفهای بازگشتی (callback refs) یک روش رایج برای دسترسی به گرههای DOM در React بودند. در حالی که رفهای بازگشتی هنوز معتبر هستند، createRef
رویکردی سادهتر و کمکلامتر، به ویژه در کامپوننتهای کلاسی، ارائه میدهد.
رف بازگشتی (callback ref) تابعی است که React آن را با گره DOM یا نمونه کامپوننت به عنوان آرگومان فراخوانی میکند. شما این تابع را به ویژگی ref
یک عنصر اختصاص میدهید:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = null;
this.setRef = element => {
this.myRef = element;
};
}
componentDidMount() {
if (this.myRef) {
this.myRef.focus();
}
}
render() {
return ;
}
}
در حالی که این رویکرد کار میکند، مدیریت آن میتواند پیچیدهتر باشد، به خصوص هنگام کار با چندین رف. createRef
این فرآیند را با ارائه یک شیء رف اختصاصی ساده میکند.
تفاوتهای کلیدی:
- خوانایی:
createRef
به طور کلی خواناتر و فهم آن آسانتر در نظر گرفته میشود. - یکنواختی:
createRef
راهی یکنواخت برای ایجاد و دسترسی به رفها فراهم میکند. - عملکرد: در برخی موارد، رفهای بازگشتی میتوانند باعث رندرهای مجدد غیرضروری شوند زیرا تابع بازگشتی در هر رندر یک تابع جدید است.
createRef
از این مشکل جلوگیری میکند.
بهترین شیوهها برای استفاده از createRef
برای اطمینان از عملکرد بهینه و قابلیت نگهداری، این بهترین شیوهها را هنگام استفاده از createRef
دنبال کنید:
- از
createRef
در کامپوننتهای کلاسی استفاده کنید:createRef
برای استفاده در کامپوننتهای کلاسی طراحی شده است. برای کامپوننتهای تابعی، از هوکuseRef
استفاده کنید. - از استفاده بیش از حد از رفها خودداری کنید: رفها باید به ندرت استفاده شوند. استفاده بیش از حد از رفها میتواند منجر به کدی شود که نگهداری و درک آن دشوار است. تا حد امکان رویکردهای اعلانی (declarative) را ترجیح دهید.
- بررسی Null بودن: همیشه قبل از دسترسی به ویژگی
current
رف، بررسی کنید که null نباشد، به خصوص در متد چرخه حیاتcomponentDidMount
. گره DOM ممکن است بلافاصله پس از mount شدن کامپوننت در دسترس نباشد.componentDidMount() { if (this.myRef.current) { this.myRef.current.focus(); } }
- از تغییر مستقیم DOM خودداری کنید: در حالی که رفها دسترسی به DOM را فراهم میکنند، از تغییر مستقیم DOM خودداری کنید مگر اینکه کاملاً ضروری باشد. DOM مجازی React راهی کارآمد برای بهروزرسانی UI فراهم میکند و دستکاری مستقیم DOM میتواند در فرآیند رندرینگ React اختلال ایجاد کند.
- در صورت لزوم رفها را پاکسازی کنید: در برخی موارد، ممکن است نیاز به پاکسازی رفها هنگام unmount شدن یک کامپوننت داشته باشید. این امر به ویژه هنگام کار با کتابخانههای شخص ثالث که ممکن است ارجاعاتی به عناصر DOM داشته باشند، مهم است.
createRef
در کامپوننتهای تابعی با هوکها
در حالی که createRef
عمدتاً در کامپوننتهای کلاسی استفاده میشود، کامپوننتهای تابعی میتوانند با استفاده از هوک useRef
به عملکرد مشابهی دست یابند. useRef
یک شیء رف قابل تغییر برمیگرداند که ویژگی .current
آن با آرگومان ارسال شده (initialValue
) مقداردهی اولیه میشود. شیء بازگشتی برای تمام طول عمر کامپوننت باقی میماند.
import React, { useRef, useEffect } from 'react';
function MyFunctionalComponent() {
const inputRef = useRef(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);
return ;
}
در این مثال، useRef(null)
یک شیء رف ایجاد میکند که به متغیر inputRef
اختصاص داده میشود. هوک useEffect
برای فوکوس کردن روی فیلد ورودی پس از رندر شدن کامپوننت استفاده میشود. آرایه وابستگی خالی []
تضمین میکند که این اثر (effect) فقط یک بار، پس از رندر اولیه، اجرا شود.
موارد استفاده پیشرفته و ملاحظات
فراتر از موارد استفاده پایه، createRef
میتواند در سناریوهای پیشرفتهتری به کار گرفته شود:
- فوروارد کردن رفها (Forwarding Refs): ریاکت مکانیزمی به نام
React.forwardRef
فراهم میکند که به شما امکان میدهد یک رف را از طریق یک کامپوننت به یکی از فرزندانش منتقل کنید. این زمانی مفید است که نیاز به دسترسی به یک گره DOM در داخل یک کامپوننت فرزند از کامپوننت والد دارید.import React, { forwardRef } from 'react'; const FancyInput = forwardRef((props, ref) => ( )); class ParentComponent extends React.Component { constructor(props) { super(props); this.inputRef = React.createRef(); } componentDidMount() { this.inputRef.current.focus(); } render() { return
; } } در این مثال، کامپوننت
FancyInput
ازforwardRef
برای انتقال رف به عنصر ورودی زیرین استفاده میکند. سپس کامپوننتParentComponent
میتواند از طریق رف به عنصر ورودی دسترسی داشته باشد و آن را دستکاری کند. - کامپوننتهای مرتبه بالاتر (HOCs): هنگام استفاده از کامپوننتهای مرتبه بالاتر (HOCs)، ممکن است نیاز به مدیریت دقیق رفها داشته باشید. اگر HOC یک کامپوننتی را که از رفها استفاده میکند در بر میگیرد، باید اطمینان حاصل کنید که رفها به درستی فوروارد میشوند.
import React, { forwardRef } from 'react'; function withRef(WrappedComponent) { const WithRef = forwardRef((props, ref) => { return
; }); WithRef.displayName = `withRef(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`; return WithRef; } class MyComponent extends React.Component { render() { return My Component; } } const EnhancedComponent = withRef(MyComponent); - رندرینگ سمت سرور (SSR): هنگام استفاده از رندرینگ سمت سرور، آگاه باشید که رفها ممکن است در طول رندر اولیه در سرور در دسترس نباشند. این به این دلیل است که DOM در سرور موجود نیست. شما باید فقط پس از mount شدن کامپوننت در سمت کلاینت به رفها دسترسی داشته باشید.
نتیجهگیری
createRef
ابزاری قدرتمند برای دسترسی به گرههای DOM و نمونههای کامپوننت در React است. با درک کاربرد، مزایا و بهترین شیوههای آن، میتوانید به طور مؤثر از رفها برای ساخت رابطهای کاربری تعاملیتر و پویاتر استفاده کنید. چه در حال فوکوس کردن روی ورودیهای متنی، مدیریت پخش رسانه یا یکپارچهسازی با کتابخانههای شخص ثالث باشید، createRef
راهی کنترلشده و کارآمد برای تعامل با DOM فراهم میکند.
به یاد داشته باشید که از createRef
با احتیاط استفاده کنید و تا حد امکان رویکردهای اعلانی را ترجیح دهید. با پیروی از دستورالعملهای ذکر شده در این راهنما، میتوانید اطمینان حاصل کنید که برنامههای React شما کارآمد، قابل نگهداری و مقیاسپذیر هستند.
همانطور که سفر خود را با React ادامه میدهید، تسلط بر createRef
بدون شک یک مهارت ارزشمند در جعبه ابزار توسعه شما خواهد بود. به آزمایش، کاوش در موارد استفاده مختلف و پالایش درک خود از این ویژگی ضروری React ادامه دهید.