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

🆔 Bài 15: useId & useSyncExternalStore

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

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

1. useId - Unique IDs An Toàn

import { useId } from 'react';

function FormField({ label, type = 'text' }) {
    const id = useId(); // Tạo unique ID, safe cho SSR

    return (
        <div>
            <label htmlFor={id}>{label}</label>
            <input id={id} type={type} />
            <p id={`${id}-hint`}>Hint text</p>
        </div>
    );
}

// Sử dụng: mỗi instance có ID khác nhau
<FormField label="Email" />     {/* id=":r1:" */}
<FormField label="Password" />  {/* id=":r2:" */}
⚠️ Không dùng useId cho: key prop trong lists, CSS selectors. useId dành cho liên kết HTML attributes (htmlFor, aria-describedby).

2. useSyncExternalStore

Đồng bộ React với state từ bên ngoài (browser APIs, third-party stores):

import { useSyncExternalStore } from 'react';

// Custom hook: theo dõi online status
function useOnlineStatus() {
    return useSyncExternalStore(
        // subscribe: đăng ký listener
        (callback) => {
            window.addEventListener('online', callback);
            window.addEventListener('offline', callback);
            return () => {
                window.removeEventListener('online', callback);
                window.removeEventListener('offline', callback);
            };
        },
        // getSnapshot: lấy giá trị hiện tại
        () => navigator.onLine,
        // getServerSnapshot (SSR)
        () => true
    );
}

function StatusBar() {
    const isOnline = useOnlineStatus();
    return <p>{isOnline ? '🟢 Online' : '🔴 Offline'}</p>;
}

// Window size hook
function useWindowWidth() {
    return useSyncExternalStore(
        (cb) => { window.addEventListener('resize', cb); return () => window.removeEventListener('resize', cb); },
        () => window.innerWidth,
        () => 1024
    );
}

📝 Tóm Tắt