Mục lục

Control Props: Controlled & Uncontrolled Hybrid

Làm sao để Component vừa hoạt động độc lập (Uncontrolled), vừa có thể nhận prop value từ ngoài (Controlled) khi cần? Pattern 'useControlled' giống MUI.

Bạn viết 1 cái <Toggle />. User A muốn: <Toggle /> (Tự quản lý state bật tắt). User B muốn: <Toggle on={isOn} onChange={setOn} /> (Component cha quản lý).

Làm sao đáp ứng cả 2?

1. Logic Hybrid

Chúng ta cần kiểm tra: Nếu user truyền prop value -> Dùng mode Controlled. Nếu không -> Dùng mode Uncontrolled (state nội bộ).

tsx:
function useControlled({ value, defaultValue, onChange }) {
  const [internalValue, setInternalValue] = useState(defaultValue);

  const isControlled = value !== undefined;
  
  // Nếu controlled -> dùng prop. Nếu không -> dùng state nội bộ.
  const currentValue = isControlled ? value : internalValue;

  const setValue = (newValue) => {
    // Luôn gọi callback ra ngoài
    if (onChange) onChange(newValue);
    
    // Chỉ update state nội bộ nếu là Uncontrolled
    if (!isControlled) {
      setInternalValue(newValue);
    }
  };

  return [currentValue, setValue];
}

2. Usage

tsx:
function Toggle({ on, defaultOn = false, onChange }) {
  const [isOn, setIsOn] = useControlled({
    value: on,
    defaultValue: defaultOn,
    onChange
  });

  return <button onClick={() => setIsOn(!isOn)}>{isOn ? 'ON' : 'OFF'}</button>;
}

// Case 1: Uncontrolled (Tự sướng)
<Toggle defaultOn={true} />

// Case 2: Controlled (Cha quản lý)
<Toggle on={appState} onChange={setAppState} />

Kết luận

Đây là bí mật đằng sau sự linh hoạt của các thư viện lớn như MUI, Ant Design. Pattern này giúp component của bạn dễ tính hơn, ai dùng kiểu nào cũng chiều được.

Quảng cáo
mdhorizontal