useRef hook
useState өгөгдөл хадгалахад ашиглагдана — гэхдээ state өөрчлөгдөх бүрт component дахин рендер болдог. Заримдаа рендер хийлгүйгээр утга хадгалах, эсвэл DOM элементэд шууд хандах хэрэгтэй болдог. Энэ хоёр хэрэгцээг useRef хангадаг. Нэрэнд нь "ref" буюу reference буюу лавлагаа гэдэг утга агуулагддаг.
useRef үндэс
useRef нь { current: утга } хэлбэртэй объект буцаадаг. current шинж чанарыг унших ба бичих боломжтой — ялгаатай нь энэ нь рендер өдөөдөггүй:
import { useRef } from "react";
function RefDemo() {
const countRef = useRef(0);
function handleClick() {
// current-г өөрчилнэ — рендер болохгүй
countRef.current += 1;
console.log("Дарсан тоо:", countRef.current);
}
return (
<div>
{/* Энэ тоо дэлгэцэнд шинэчлэгдэхгүй — рендер болдоггүй учраас */}
<p>Ref утга: {countRef.current}</p>
<button onClick={handleClick}>Дарах</button>
</div>
);
}
countRef.current нэмэгдэж байгаа ч дэлгэцэнд харагдахгүй. Дэлгэц шинэчлэх шаардлагатай бол useState ашигла — зөвхөн рендергүйгээр утга хадгалах шаардлагатай бол useRef.
DOM элементэд хандах
useRef-н хамгийн нийтлэг хэрэглээ бол DOM элементийг шууд барьж авах явдал юм. ref props-г JSX элементэд дамжуулбал current тухайн DOM node болно:
import { useRef } from "react";
function AutoFocusInput() {
const inputRef = useRef(null);
function handleFocus() {
// DOM элементийн .focus() аргыг шууд дуудна
inputRef.current.focus();
}
function handleClear() {
inputRef.current.value = "";
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} type="text" placeholder="Энд бичнэ үү..." />
<button onClick={handleFocus}>Focus хийх</button>
<button onClick={handleClear}>Цэвэрлэх</button>
</div>
);
}
inputRef.current нь яг document.getElementById(...) буцаадаг шиг DOM элементийг буцаана — гэхдээ React-н арга замаар, id хэрэглэхгүйгээр.
useEffect-тэй хослуулах
Component дэлгэцэнд гарсны дараа автоматаар focus хийх нийтлэг хэрэглээ:
import { useRef, useEffect } from "react";
function SearchBar() {
const inputRef = useRef(null);
// Хуудас ачаалагдахад автоматаар focus хийнэ
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<div>
<input ref={inputRef} type="search" placeholder="Хайх..." />
</div>
);
}
import { useRef, useEffect, useState } from "react";
function VideoPlayer({ src, isPlaying }) {
const videoRef = useRef(null);
useEffect(() => {
if (!videoRef.current) return;
if (isPlaying) {
videoRef.current.play();
} else {
videoRef.current.pause();
}
}, [isPlaying]);
return <video ref={videoRef} src={src} />;
}
Өмнөх утгыг хадгалах
useRef нь render хооронд утгыг хадгалдаг тул өмнөх state-г хадгалахад ашиглаж болно:
import { useRef, useEffect, useState } from "react";
function usePrevious(value) {
const prevRef = useRef();
useEffect(() => {
prevRef.current = value;
});
return prevRef.current;
}
function PriceTracker() {
const [price, setPrice] = useState(1000);
const prevPrice = usePrevious(price);
const change = prevPrice !== undefined ? price - prevPrice : 0;
const color = change > 0 ? "#4ade80" : change < 0 ? "#fb7185" : "#94a3b8";
return (
<div>
<p>Одоогийн үнэ: {price}₮</p>
{prevPrice !== undefined && (
<p style={{ color }}>
Өмнөх: {prevPrice}₮ ({change > 0 ? "+" : ""}
{change}₮)
</p>
)}
<button onClick={() => setPrice((p) => p + 50)}>+50₮</button>
<button onClick={() => setPrice((p) => p - 30)}>-30₮</button>
</div>
);
}
Interval ID хадгалах
Interval эсвэл timeout-н ID-г useRef-д хадгалах нь нийтлэг хэлбэр — тэдгээр нь рендер өдөөх шаардлагагүй:
import { useRef, useState } from "react";
function Stopwatch() {
const [elapsed, setElapsed] = useState(0);
const [running, setRunning] = useState(false);
const intervalRef = useRef(null);
function start() {
if (running) return;
setRunning(true);
intervalRef.current = setInterval(() => {
setElapsed((prev) => prev + 10);
}, 10);
}
function stop() {
clearInterval(intervalRef.current);
setRunning(false);
}
function reset() {
clearInterval(intervalRef.current);
setRunning(false);
setElapsed(0);
}
const seconds = (elapsed / 1000).toFixed(2);
return (
<div>
<p>{seconds} секунд</p>
<button onClick={start} disabled={running}>
Эхлэх
</button>
<button onClick={stop} disabled={!running}>
Зогсоох
</button>
<button onClick={reset}>Дахилт</button>
</div>
);
}
intervalRef.current = setInterval(...) нь рендер өдөөхгүй тул state ашиглахаас илүү тохиромжтой.
Дараагийн хичээлд:
useContext hook ашиглан props дамжуулалтгүйгээр component мод даяар өгөгдөл хуваалцах аргыг судална. Theme, хэрэглэгчийн мэдээлэл зэрэг глобал state-г хэрхэн зохицуулах талаар ойлгоно.