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

⏳ Bài 14: useTransition & useDeferredValue

⏱️ Thời gian đọc: 15 phút | 📚 Độ khó: Nâng cao

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

1. useTransition

useTransition cho phép đánh dấu một state update là "không khẩn cấp", giúp React ưu tiên cập nhật UI khẩn cấp trước.

import { useState, useTransition } from 'react';

function SearchPage() {
    const [query, setQuery] = useState('');
    const [results, setResults] = useState([]);
    const [isPending, startTransition] = useTransition();

    const handleSearch = (e) => {
        const value = e.target.value;
        // Cập nhật input NGAY LẬP TỨC (khẩn cấp)
        setQuery(value);

        // Cập nhật results TRỄ hơn (không khẩn cấp)
        startTransition(() => {
            const filtered = heavySearch(value); // Tính toán nặng
            setResults(filtered);
        });
    };

    return (
        <div>
            <input value={query} onChange={handleSearch} placeholder="Tìm kiếm..." />
            {isPending && <p>Đang tìm...</p>}
            <ul>
                {results.map(r => <li key={r.id}>{r.name}</li>)}
            </ul>
        </div>
    );
}
💡 Khi nào dùng: Khi bạn có 2 state updates, 1 cần phản hồi ngay (input, button) và 1 có thể chờ (filter list, render chart).

2. useDeferredValue

useDeferredValue trì hoãn cập nhật một giá trị cho đến khi React rảnh:

import { useState, useDeferredValue, useMemo } from 'react';

function FilteredList({ items }) {
    const [filter, setFilter] = useState('');
    const deferredFilter = useDeferredValue(filter);

    // useMemo + deferredValue: list cập nhật trễ, input mượt
    const filteredItems = useMemo(() => {
        return items.filter(item =>
            item.name.toLowerCase().includes(deferredFilter.toLowerCase())
        );
    }, [items, deferredFilter]);

    const isStale = filter !== deferredFilter;

    return (
        <div>
            <input
                value={filter}
                onChange={e => setFilter(e.target.value)}
                placeholder="Filter..."
            />
            <div style={{ opacity: isStale ? 0.5 : 1 }}>
                {filteredItems.map(item => (
                    <div key={item.id}>{item.name}</div>
                ))}
            </div>
        </div>
    );
}

3. useTransition vs useDeferredValue

Tiêu chíuseTransitionuseDeferredValue
WrapState update (setter)Giá trị (value)
Khi nàoBạn kiểm soát setStateNhận value từ props/parent
isPendingSo sánh value vs deferred

📝 Tóm Tắt