← Về danh sách bài họcBài 8/25

📍 Bài 8: useRef - Tham Chiếu DOM & Giá Trị Persistent

⏱️ Thời gian đọc: 12 phút | 📚 Độ khó: Trung bình

🎯 Sau bài học này, bạn sẽ:

1. useRef Là Gì?

useRef tạo một object { current: value } tồn tại xuyên suốt lifecycle của component. Thay đổi .current KHÔNG gây re-render.

import { useRef, useState, useEffect } from 'react';

function RenderCounter() {
    const [count, setCount] = useState(0);
    const renderCount = useRef(0);

    // Tăng mỗi render, nhưng KHÔNG gây re-render thêm
    renderCount.current += 1;

    return (
        <div>
            <p>Count: {count}</p>
            <p>Render lần thứ: {renderCount.current}</p>
            <button onClick={() => setCount(c => c + 1)}>+1</button>
        </div>
    );
}

2. Truy Cập DOM Elements

function SearchBox() {
    const inputRef = useRef(null);

    // Focus vào input khi mount
    useEffect(() => {
        inputRef.current.focus();
    }, []);

    const handleSubmit = () => {
        alert(`Tìm: ${inputRef.current.value}`);
        inputRef.current.value = '';
        inputRef.current.focus();
    };

    return (
        <div>
            <input ref={inputRef} placeholder="Tìm kiếm..." />
            <button onClick={handleSubmit}>🔍</button>
        </div>
    );
}

// Video player
function VideoPlayer({ src }) {
    const videoRef = useRef(null);

    return (
        <div>
            <video ref={videoRef} src={src} />
            <button onClick={() => videoRef.current.play()}>▶️ Play</button>
            <button onClick={() => videoRef.current.pause()}>⏸️ Pause</button>
        </div>
    );
}

3. Lưu Giá Trị Previous

function usePrevious(value) {
    const ref = useRef();
    useEffect(() => {
        ref.current = value;
    }, [value]);
    return ref.current;
}

// Sử dụng
function PriceTracker({ price }) {
    const prevPrice = usePrevious(price);

    return (
        <div>
            <p>Giá hiện tại: {price}đ</p>
            <p>Giá trước: {prevPrice}đ</p>
            <p>{price > prevPrice ? '📈 Tăng' : '📉 Giảm'}</p>
        </div>
    );
}

4. forwardRef

import { forwardRef, useRef } from 'react';

// Component con nhận ref từ cha
const FancyInput = forwardRef((props, ref) => (
    <input
        ref={ref}
        className="fancy-input"
        placeholder={props.placeholder}
    />
));

// Component cha
function Form() {
    const inputRef = useRef(null);

    return (
        <div>
            <FancyInput ref={inputRef} placeholder="Email" />
            <button onClick={() => inputRef.current.focus()}>
                Focus Input
            </button>
        </div>
    );
}

📝 Tóm Tắt