با تسلط بر ref های React، به طور مستقیم DOM را دستکاری کنید، فوکوس را مدیریت کنید، کتابخانههای جانبی را ادغام کرده و عملکرد UI را بهینه کنید. راهنمای جامع برای توسعه مدرن React.
الگوهای Ref در React: تکنیکهای دستکاری DOM برای رابطهای کاربری پویا
React، یک کتابخانه قدرتمند جاوا اسکریپت برای ساخت رابطهای کاربری، اغلب رویکردی اعلانی (declarative) را برای توسعه UI تشویق میکند. با این حال، گاهی اوقات، دستکاری مستقیم مدل شیء سند (DOM) ضروری میشود. اینجاست که ref های React وارد عمل میشوند. Ref ها راهی برای دسترسی به گرههای DOM یا عناصر React ایجاد شده در متد رندر فراهم میکنند. این راهنمای جامع به بررسی الگوها و تکنیکهای مختلف ref در React برای دستکاری مؤثر DOM، مدیریت فوکوس، ادغام با کتابخانههای جانبی و بهینهسازی عملکرد UI میپردازد. ما به نمونههای عملی و بهترین شیوههای مناسب برای مخاطبان جهانی توسعهدهندگان React خواهیم پرداخت.
درک Ref ها در React
در هسته خود، یک ref یک شیء ساده جاوا اسکریپت با یک پراپرتی current
است. این پراپرتی قابل تغییر است و به شما امکان میدهد هر مقداری، از جمله یک گره DOM یا یک نمونه کامپوننت React را در آن ذخیره کنید. React دو راه اصلی برای ایجاد ref ها فراهم میکند: React.createRef()
(برای کامپوننتهای کلاسی) و هوک useRef()
(برای کامپوننتهای تابعی).
React.createRef() (کامپوننتهای کلاسی)
React.createRef()
یک شیء ref ایجاد میکند که به یک پراپرتی از نمونه کامپوننت کلاسی اختصاص داده میشود. این ref در طول چرخه حیات کامپوننت باقی میماند.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
// Access the DOM node after the component mounts
console.log(this.myRef.current); // DOM node or null
}
render() {
return Hello, world!;
}
}
useRef() (کامپوننتهای تابعی)
هوک useRef()
یک شیء ref قابل تغییر ایجاد میکند که پراپرتی .current
آن با آرگومان ارسال شده (initialValue
) مقداردهی اولیه میشود. شیء ref بازگشتی برای تمام طول عمر کامپوننت باقی خواهد ماند.
import React, { useRef, useEffect } from 'react';
function MyFunctionalComponent() {
const myRef = useRef(null);
useEffect(() => {
// Access the DOM node after the component mounts
console.log(myRef.current); // DOM node or null
}, []); // Empty dependency array ensures this runs only once on mount
return Hello, world!;
}
کاربردهای رایج Ref ها در React
Ref ها فوقالعاده متنوع هستند و در سناریوهای مختلفی در توسعه React کاربرد دارند.
۱. دسترسی و دستکاری گرههای DOM
رایجترین مورد استفاده برای ref ها، دسترسی مستقیم و دستکاری گرههای DOM است. این برای کارهایی مانند فوکوس کردن روی یک فیلد ورودی، اسکرول کردن به یک عنصر یا اندازهگیری ابعاد آن مفید است.
import React, { useRef, useEffect } from 'react';
function FocusInput() {
const inputRef = useRef(null);
useEffect(() => {
// Focus the input field after the component mounts
if (inputRef.current) {
inputRef.current.focus();
}
}, []);
return ;
}
مثال: تصور کنید در حال ساخت یک فرم چند مرحلهای هستید. وقتی کاربر یک فیلد را تکمیل میکند، ممکن است بخواهید به طور خودکار روی ورودی بعدی فوکوس کنید. Ref ها این کار را یکپارچه میکنند.
۲. مدیریت فوکوس، انتخاب متن و پخش رسانه
Ref ها برای کنترل دقیق بر فوکوس، انتخاب متن در عناصر و مدیریت پخش رسانه (مانند ویدئو یا صدا) ضروری هستند.
import React, { useRef, useEffect } from 'react';
function VideoPlayer() {
const videoRef = useRef(null);
const playVideo = () => {
if (videoRef.current) {
videoRef.current.play();
}
};
const pauseVideo = () => {
if (videoRef.current) {
videoRef.current.pause();
}
};
return (
);
}
نکته دسترسیپذیری: هنگام استفاده از ref ها برای مدیریت فوکوس، از مدیریت صحیح فوکوس اطمینان حاصل کنید تا دسترسیپذیری برای کاربرانی که به ناوبری با صفحهکلید یا فناوریهای کمکی متکی هستند، حفظ شود. به عنوان مثال، پس از باز شدن یک مودال، بلافاصله فوکوس را روی اولین عنصر قابل فوکوس در داخل مودال قرار دهید.
۳. ادغام با کتابخانههای جانبی
بسیاری از کتابخانههای جاوا اسکریپت جانبی مستقیماً DOM را دستکاری میکنند. Ref ها پلی بین مدل اعلانی React و این کتابخانههای دستوری (imperative) فراهم میکنند.
import React, { useRef, useEffect } from 'react';
import Chart from 'chart.js/auto'; // Example: Using Chart.js
function ChartComponent() {
const chartRef = useRef(null);
useEffect(() => {
if (chartRef.current) {
const ctx = chartRef.current.getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
}
}, []);
return ;
}
نکته بینالمللیسازی: هنگام ادغام کتابخانههای جانبی که با تاریخ، اعداد یا ارزها سروکار دارند، اطمینان حاصل کنید که آنها به درستی برای پشتیبانی از locale کاربر پیکربندی شدهاند. بسیاری از کتابخانهها گزینههایی برای تعیین locale مورد نظر ارائه میدهند. به عنوان مثال، کتابخانههای قالببندی تاریخ باید با زبان و منطقه کاربر مقداردهی اولیه شوند تا تاریخها را در قالب صحیح نمایش دهند (مثلاً MM/DD/YYYY در مقابل DD/MM/YYYY).
۴. راهاندازی انیمیشنهای دستوری
در حالی که کتابخانههای React مانند Framer Motion و React Transition Group برای اکثر نیازهای انیمیشن ترجیح داده میشوند، میتوان از ref ها برای انیمیشنهای دستوری زمانی که کنترل دقیقتری لازم است، استفاده کرد.
import React, { useRef, useEffect } from 'react';
function FadeIn() {
const elementRef = useRef(null);
useEffect(() => {
const element = elementRef.current;
if (element) {
element.style.opacity = 0; // Initially hidden
let opacity = 0;
const intervalId = setInterval(() => {
opacity += 0.05;
element.style.opacity = opacity;
if (opacity >= 1) {
clearInterval(intervalId);
}
}, 20); // Adjust interval for speed
return () => clearInterval(intervalId); // Cleanup on unmount
}
}, []);
return Fade In!;
}
۵. اندازهگیری ابعاد عنصر
Ref ها به شما امکان میدهند ابعاد (عرض، ارتفاع) عناصر را در DOM به دقت اندازهگیری کنید. این برای طرحبندیهای واکنشگرا، موقعیتیابی پویا و ایجاد جلوههای بصری سفارشی مفید است.
import React, { useRef, useEffect, useState } from 'react';
function MeasureElement() {
const elementRef = useRef(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const element = elementRef.current;
if (element) {
const width = element.offsetWidth;
const height = element.offsetHeight;
setDimensions({ width, height });
}
}, []);
return (
Measure This Element
Width: {dimensions.width}px
Height: {dimensions.height}px
);
}
الگوهای پیشرفته Ref
فراتر از استفاده اولیه از createRef
و useRef
, چندین الگوی پیشرفته وجود دارد که از ref ها برای سناریوهای پیچیدهتر بهره میبرند.
۱. Ref های Callback
Ref های Callback روشی انعطافپذیرتر برای دسترسی به گرههای DOM فراهم میکنند. به جای اختصاص یک شیء ref، شما یک تابع را به خصوصیت ref
اختصاص میدهید. React این تابع را با گره DOM هنگامی که کامپوننت mount میشود و با null
هنگامی که unmount میشود، فراخوانی میکند.
import React, { useState } from 'react';
function CallbackRefExample() {
const [element, setElement] = useState(null);
const setRef = (node) => {
setElement(node);
};
return (
This element's ref is being managed by a callback.
{element && Element: {element.tagName}
}
);
}
Ref های Callback به ویژه زمانی مفید هستند که نیاز به انجام اقدامات اضافی هنگام تنظیم یا پاک شدن ref دارید.
۲. ارسال Ref ها (forwardRef)
React.forwardRef
تکنیکی است که به یک کامپوننت اجازه میدهد یک ref را که از کامپوننت والد خود ارسال شده است، دریافت کند. این زمانی مفید است که میخواهید یک گره DOM از یک کامپوننت فرزند را در اختیار والد آن قرار دهید.
import React, { forwardRef } from 'react';
const MyInput = forwardRef((props, ref) => {
return ;
});
function ParentComponent() {
const inputRef = React.useRef(null);
const focusInput = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
);
}
در این مثال، MyInput
ref را به عنصر input زیرین ارسال میکند و به ParentComponent
اجازه میدهد مستقیماً به input دسترسی داشته باشد و آن را دستکاری کند.
۳. در اختیار قرار دادن متدهای کامپوننت با Ref ها
Ref ها همچنین میتوانند برای در اختیار قرار دادن متدها از یک کامپوننت فرزند به والد آن استفاده شوند. این برای ایجاد کامپوننتهای قابل استفاده مجدد با API های دستوری مفید است.
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
getValue: () => {
return inputRef.current.value;
}
}));
return ;
});
function ParentComponent() {
const fancyInputRef = useRef(null);
const handleFocus = () => {
fancyInputRef.current.focus();
};
const handleGetValue = () => {
alert(fancyInputRef.current.getValue());
};
return (
);
}
هوک useImperativeHandle
به شما امکان میدهد مقدار نمونهای را که هنگام استفاده از forwardRef
در اختیار کامپوننتهای والد قرار میگیرد، سفارشی کنید. این امکان دسترسی کنترل شده به متدهای فرزند را فراهم میکند.
بهترین شیوهها برای استفاده از Ref های React
در حالی که ref ها قابلیتهای قدرتمندی را فراهم میکنند، استفاده هوشمندانه از آنها و پیروی از بهترین شیوهها بسیار مهم است.
- از دستکاری بیش از حد DOM خودداری کنید: رویکرد اعلانی React به طور کلی کارآمدتر است. فقط زمانی از ref ها استفاده کنید که برای کارهایی که به راحتی از طریق مدیریت state در React قابل دستیابی نیستند، ضروری باشد.
- از Ref ها به ندرت استفاده کنید: استفاده بیش از حد از ref ها میتواند منجر به کدی شود که نگهداری و درک آن دشوارتر است.
- به چرخه حیات کامپوننت توجه داشته باشید: اطمینان حاصل کنید که به پراپرتی
.current
یک ref فقط پس از mount شدن کامپوننت (مثلاً درcomponentDidMount
یاuseEffect
) دسترسی پیدا میکنید. دسترسی به آن قبل از این مرحله میتواند منجر به مقادیرnull
شود. - Ref ها را پاکسازی کنید: هنگام استفاده از ref های callback، اطمینان حاصل کنید که هنگام unmount شدن کامپوننت، ref را به
null
تنظیم میکنید تا از نشت حافظه جلوگیری شود. - جایگزینها را در نظر بگیرید: قبل از استفاده از ref ها، بررسی کنید که آیا مدیریت state در React یا کامپوننتهای کنترلشده میتوانند رفتار مورد نظر را به دست آورند یا خیر.
- دسترسیپذیری: هنگام دستکاری فوکوس، اطمینان حاصل کنید که برنامه برای کاربران دارای معلولیت قابل دسترس باقی میماند.
ملاحظات جهانی برای استفاده از Ref
هنگام ساخت برنامهها برای مخاطبان جهانی، جنبههای زیر را هنگام استفاده از ref ها در نظر بگیرید:
- طرحبندیهای راست به چپ (RTL): هنگام دستکاری عناصر DOM مربوط به طرحبندی (مانند اسکرول کردن)، اطمینان حاصل کنید که کد شما به درستی طرحبندیهای RTL را برای زبانهایی مانند عربی و عبری مدیریت میکند. از خواصی مانند
scrollLeft
وscrollWidth
با دقت استفاده کنید و به طور بالقوه آنها را بر اساس جهت طرحبندی نرمالسازی کنید. - ویرایشگرهای روش ورودی (IMEs): آگاه باشید که کاربران در برخی مناطق ممکن است از IMEs برای وارد کردن متن استفاده کنند. هنگام مدیریت فوکوس یا انتخاب متن، اطمینان حاصل کنید که کد شما به درستی با IMEs تعامل دارد و با ورودی کاربر تداخل نمیکند.
- بارگذاری فونت: اگر قبل از بارگذاری کامل فونتها ابعاد عنصر را اندازهگیری میکنید، اندازهگیریهای اولیه ممکن است نادرست باشند. از تکنیکهایی برای اطمینان از بارگذاری فونتها قبل از تکیه بر این اندازهگیریها استفاده کنید (مثلاً با استفاده از
document.fonts.ready
). سیستمهای نوشتاری مختلف (مانند لاتین، سیریلیک، CJK) اندازهها و معیارهای فونت بسیار متفاوتی دارند. - ترجیحات کاربر: ترجیحات کاربر برای انیمیشنها و انتقالها را در نظر بگیرید. برخی از کاربران ممکن است حرکت کاهش یافته را ترجیح دهند. هنگام استفاده از ref ها برای راهاندازی انیمیشنها به این ترجیحات احترام بگذارید. از کوئری رسانه CSS `prefers-reduced-motion` برای تشخیص ترجیحات کاربر استفاده کنید.
نتیجهگیری
Ref های React ابزاری قدرتمند برای دستکاری مستقیم DOM، مدیریت فوکوس، ادغام با کتابخانههای جانبی و بهینهسازی عملکرد UI هستند. با درک الگوهای مختلف ref و پیروی از بهترین شیوهها، میتوانید به طور مؤثر از ref ها استفاده کنید و در عین حال مزایای رویکرد اعلانی React را حفظ کنید. به یاد داشته باشید که جنبههای دسترسیپذیری جهانی و بینالمللیسازی را برای ایجاد برنامههای فراگیر و کاربرپسند برای مخاطبان متنوع در نظر بگیرید. با برنامهریزی و اجرای دقیق، ref های React میتوانند به طور قابل توجهی قابلیتها و پاسخگویی برنامههای React شما را افزایش دهند.