React-focused. Hooks là modern approach, classics vẫn quan trọng.
6. Custom Hooks
Modern
Là gì: Tách stateful logic ra hàm useXxx().
Khi dùng: Logic 2+ component cùng dùng.
function useDebouncedValue<T>(value: T, delayMs: number): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const id = setTimeout(() => setDebounced(value), delayMs);
return () => clearTimeout(id);
}, [value, delayMs]);
return debounced;
}
// const debouncedSearch = useDebouncedValue(search, 300);
Interview Q: Khi nào extract? → Rule of 3 — chờ thấy 3 lần duplicate mới extract.
7. Container / Presentational
Classic
Là gì: Tách "smart" (fetch + state) khỏi "dumb" (chỉ render).
Khi dùng: Storybook + design system. Tanstack Query nay thay phần lớn.
// Container — fetches data
function UserListContainer() {
const { data, isLoading } = useUsers();
if (isLoading) return <Spinner />;
return <UserList users={data} />;
}
// Presentational — pure UI
function UserList({ users }: { users: User[] }) {
return <ul>{users.map(u => <li>{u.name}</li>)}</ul>;
}
Interview Q: Còn dùng không? → Vẫn cho design system: Presentational components dễ document và visual test.
8. Compound Components
Composition
Là gì: Component chia nhiều sub-component, share state ngầm qua Context.
Khi dùng: Tabs, Accordion, Select — cần flexibility.
<Tabs defaultValue="profile">
<Tabs.List>
<Tabs.Tab value="profile">Profile</Tabs.Tab>
<Tabs.Tab value="settings">Settings</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="profile">...</Tabs.Panel>
<Tabs.Panel value="settings">...</Tabs.Panel>
</Tabs>
Interview Q: Vì sao không 1 component lớn nhận tabs prop? → Compound = layout flexibility, dev tự custom.
9. Provider (Context)
Shared State
Là gì: Wrap subtree, share state cho descendants không cần prop drilling.
Khi dùng: Theme, Auth, i18n — data ÍT thay đổi.
const AuthContext = createContext<AuthState | null>(null);
function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
return <AuthContext.Provider value={{ user, setUser }}>
{children}
</AuthContext.Provider>;
}
function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be inside AuthProvider');
return ctx;
}
Interview Q: Khi nào Context KHÔNG nên dùng? → Data đổi mỗi giây → re-render storm → dùng Zustand/Redux.
10. Render Props / HOC
Legacy
Là gì: Cách cũ share logic giữa components — trước khi có hooks.
Khi dùng: Hiện hầu như thay bằng hooks. Vẫn thấy ở React Router < v6, Formik, etc.
// Render prop
<DataFetcher url="/api/users">
{({ data, loading }) => loading ? <Spinner /> : <List items={data} />}
</DataFetcher>
// HOC (Higher-Order Component)
const EnhancedComponent = withAuth(MyComponent);
Interview Q: Render Props vs Custom Hooks? → Hooks won. Không thêm tree depth, không có "wrapper hell", reuse state logic mà không reuse UI.