- Redux Toolkit (RTK) là gì? Tại sao nên dùng RTK thay vì Redux thuần?
RTK là cách duy nhất được khuyến nghị để viết Redux hiện đại — createSlice gộp actions+reducer, Immer cho phép write mutable syntax, RTK Query thay thế thunk cho data fetching. Redux Toolkit (RTK) là bộ công cụ chính thức và là cách duy nhất…
- createSlice trong RTK hoạt động như thế nào?
createSlice gộp actions, action types, và reducer vào một chỗ — Immer bên trong cho phép viết mutable syntax mà vẫn immutable thật sự. createSlice là API quan trọng nhất của RTK, nhận object gồm name (prefix cho action types), initialState, và reducers (object chứa…
- createAsyncThunk được dùng để làm gì? Các trạng thái lifecycle của nó là gì?
createAsyncThunk tạo thunk action creator cho async logic (gọi API) và tự dispatch ba lifecycle action: pending (bắt đầu → bật loading), fulfilled (thành công → cập nhật data), rejected (thất bại → hiện lỗi). Xử lý trong slice bằng extraReducers với builder pattern: -…
- Selector trong Redux là gì? Tại sao nên dùng createSelector?
createSelector memoize kết quả selector — chỉ recompute khi input thay đổi, tránh re-render không cần thiết khi filter/map trả về reference mới. Selector là function nhận toàn bộ Redux state và trích xuất/tính toán phần data cần thiết, ví dụ: const selectActiveTodos = state…
- RTK Query là gì? Lợi ích so với cách fetch data thủ công?
- Cách định nghĩa API với createApi trong RTK Query như thế nào?
- Redux middleware là gì? Cho ví dụ về middleware phổ biến?
Middleware là function nằm giữa dispatch(action) và reducer, có thể inspect, modify, delay, hoặc cancel action trước khi đến reducer. Flow: dispatch → middleware1 → middleware2 → reducer. Middleware phổ biến: redux-thunk (cho phép dispatch function thay vì object, xử lý async — RTK include…
- Redux DevTools hoạt động như thế nào? Tính năng time-travel debugging là gì?
- useSelector và useDispatch hook trong React-Redux hoạt động như thế nào?
useSelector nhận selector function, subscribe vào Redux store, và dùng strict === comparison (reference equality) để quyết định có re-render không. Lưu ý quan trọng: nếu selector trả về object/array mới mỗi lần gọi — ví dụ useSelector(s = s.items.filter(...)) — reference luôn khác nên…
- Khi nào nên dùng Redux và khi nào không cần?
- Zustand là gì? So sánh với Redux về độ phức tạp?
Zustand là thư viện quản lý state nhỏ gọn cho React, không yêu cầu boilerplate như Redux — không cần actions, reducers, dispatch, hay Provider wrapper. API chỉ gồm hàm create trả về một hook, state và actions định nghĩa cùng chỗ. Bundle size ~1KB…
- Cách tạo một store với Zustand như thế nào?
Dùng create từ 'zustand', truyền vào initializer nhận (set, get) và trả về object chứa cả state lẫn action trong cùng một chỗ. set() merge partial state (không cần spread toàn bộ như Redux), get() đọc state hiện tại từ bên trong action. Store trả…
- Cách định nghĩa actions trong Zustand store?
Action trong Zustand là function thường sống cùng state trong store object — không action type, không dispatch, không reducer. Ba pattern hay dùng: Nhiều lần cập nhật state trong cùng một lời gọi set được batch tự động. Lưu ý: set chỉ shallow merge…
- Zustand khác Redux như thế nào về kiến trúc?
Hai kiến trúc khác nhau từ gốc. Redux đi theo Flux: action object → dispatch → middleware → reducer → state mới. Zustand không có khái niệm action type hay reducer — chỉ là function gọi set(). Redux bắt buộc kèm theo Provider wrapper, combineReducers,…
- Làm thế nào để tránh re-render không cần thiết trong Zustand?
Luôn dùng selector cụ thể — gọi useStore() không selector là subscribe toàn bộ store, re-render khi bất kỳ state nào đổi. Zustand so sánh bằng === nên selector trả primitive thì không có vấn đề; rắc rối chỉ xảy ra khi selector tạo object/array…
- Zustand middleware là gì? Cho ví dụ về devtools middleware?
Zustand middleware wrap store creator với higher-order function — devtools, immer, persist là ba middleware phổ biến nhất; compose bằng cách nest lồng nhau, devtools ở ngoài cùng. Zustand middleware dùng pattern higher-order function wrap store creator. Import từ 'zustand/middleware'. Compose nhiều middleware bằng cú…
- persist middleware trong Zustand hoạt động như thế nào?
Middleware persist từ 'zustand/middleware' serialize state thành JSON, lưu vào storage và rehydrate khi app khởi động. - name là storage key, bắt buộc. - partialize chọn phần state cần lưu — bỏ qua loading/error state cho gọn. - storage đổi engine: sessionStorage, hoặc AsyncStorage…
- Cách chia nhỏ Zustand store thành nhiều slices?
- Cách sử dụng Zustand với TypeScript để có type safety?
- Khi nào nên chọn Zustand thay vì Redux Toolkit?
- React Query (TanStack Query) là gì? Mục đích chính của nó là gì?
React Query (nay là TanStack Query v5) là thư viện quản lý server state cho React, giải quyết bài toán mà useState + useEffect không làm tốt: fetching, caching, synchronizing và updating data từ API. Ví dụ thực tế: không cần React Query, bạn phải…
- useQuery hook hoạt động như thế nào? Các tham số cơ bản là gì?
useQuery là hook chính để đọc data, nhận 2 tham số bắt buộc: queryKey (mảng định danh duy nhất, ví dụ ['todos', { status: 'active' }]) và queryFn (async function trả về data, ví dụ () = fetch('/api/todos').then(r = r.json())). Trả về object gồm: data…
- useMutation hook dùng để làm gì? Cách xử lý optimistic updates?
useMutation xử lý write operations (POST/PUT/DELETE) — khác useQuery chỉ đọc. Cung cấp mutate() (fire-and-forget) hoặc mutateAsync() (trả về Promise). States: isPending, isError, isSuccess, data, error. Optimistic update flow: (1) onMutate: cancel ongoing queries, snapshot data cũ, set cache mới ngay → UI cập nhật…
- Cache invalidation trong React Query hoạt động như thế nào?
Cache invalidation là cơ chế đánh dấu data đã cũ (stale) để trigger refetch. Cách dùng: queryClient.invalidateQueries({ queryKey: ['todos'] }) — tất cả queries có key bắt đầu bằng 'todos' bị đánh dấu stale. Nếu component đang mount thì refetch ngay, nếu không thì refetch…
- staleTime và gcTime (cacheTime) trong React Query là gì? Sự khác biệt?
staleTime kiểm soát khi nào refetch; gcTime kiểm soát khi nào xoá cache — staleTime nên ≤ gcTime. Hai config quan trọng nhất quyết định caching behavior. staleTime (mặc định 0): thời gian data được coi là 'fresh' — trong khoảng này component mount mới…
- Tại sao React Query được coi là giải pháp 'server state' không phải 'global state'?
Có hai loại state khác nhau về bản chất: - Client state (theme, sidebar đang mở, nội dung form) — client sở hữu hoàn toàn, cập nhật là thấy ngay, và không bao giờ "cũ". - Server state (profile user, danh sách todo, catalog sản…
- Cách cấu hình React Query với QueryClient và QueryClientProvider?
QueryClient là singleton quản lý toàn bộ cache và config. Tạo BÊN NGOÀI component để không bị dựng lại sau mỗi render. defaultOptions áp cho mọi query/mutation trừ khi override ở từng query. - Mặc định retry 3 lần với exponential backoff; ví dụ trên…
- refetchOnWindowFocus trong React Query là gì? Khi nào nên tắt nó?
refetchOnWindowFocus (mặc định bật) refetch tất cả stale queries khi user quay lại tab — tắt khi data ít thay đổi hoặc refetch gây UX kém. refetchOnWindowFocus là behavior mặc định: khi user chuyển tab rồi quay lại, React Query tự động refetch tất cả…
- Prefetching trong React Query hoạt động như thế nào?
- Infinite queries trong React Query là gì? Dùng cho pagination như thế nào?
- Dependent queries trong React Query là gì?
- Cách xử lý error trong React Query?
React Query v5 đổi cách xử lý lỗi so với v4: onError toàn cục trong defaultOptions đã bị gỡ, thay bằng throwOnError hoặc meta. - retry: (failureCount, error) = error.status !== 401 && failureCount < 3 để không retry lỗi auth. - throwOnError: true đẩy…
- QueryKey trong React Query nên được thiết kế như thế nào?
QueryKey là nền của kiến trúc cache. Ba nguyên tắc: đưa MỌI dependency dùng trong queryFn vào key (['todos', userId, { status, page, sort }]); dùng array chứ đừng dùng string thuần, vì array mới invalidate fuzzy được; xếp từ tổng quát đến cụ thể…
- Optimistic updates trong React Query thực hiện như thế nào?
- Cách kết hợp React Query với Next.js Server Components?
- Jotai là gì? So sánh với Recoil?
Jotai là thư viện atomic state management tương tự Recoil nhưng nhỏ gọn hơn (~3KB vs ~21KB) và API đơn giản hơn đáng kể. Điểm khác biệt chính: Jotai không yêu cầu key string duy nhất cho mỗi atom (Recoil bắt buộc, dễ gây conflict…
- Cách tạo và sử dụng atom trong Jotai?
Primitive atom: const countAtom = atom(0) — trong component dùng useAtom(countAtom) trả về [value, setValue]. Derived read-only: const doubleAtom = atom(get = get(countAtom) 2) — dùng useAtomValue. Derived read-write: atom(get = get(baseAtom), (get, set, newVal) = set(baseAtom, newVal 2)). atomWithStorage('key', defaultVal) từ jotai/utils tự đồng…
- Async atoms trong Jotai hoạt động như thế nào?
- So sánh bundle size và performance giữa Jotai và Zustand?
- Jotai Provider là gì? Khi nào cần dùng?
Provider-less là mặc định: Jotai dùng global WeakMap store nên mọi component share cùng atom value mà không phải bọc Provider. Khi nào cần Provider: - Testing — <Provider store={createStore()} tạo store cô lập cho từng test, tránh state rò rỉ giữa các test. -…
- Khi nào nên dùng atomic state management (Jotai) thay vì Redux/Zustand?
- So sánh các thư viện quản lý state phổ biến: Redux Toolkit, Zustand, Context API, Jotai? Khi nào dùng gì?
Context API: state đơn giản, ít thay đổi (theme, auth, locale) — không cần cài thêm gì. Zustand: nhẹ (~1KB), ít boilerplate, API đơn giản, phù hợp đa số projects. Redux Toolkit: enterprise, complex state cần middleware (async thunks, saga), DevTools mạnh, team lớn cần…
- Redux Toolkit createSlice hoạt động thế nào?
createSlice kết hợp action creators + reducer trong cùng một file, dùng Immer nên có thể mutate state trực tiếp.
- QueryClientProvider là gì? Tại sao cần wrap app bằng nó?
QueryClientProvider là React Context Provider mang instance QueryClient xuống toàn bộ cây component. QueryClient chính là bộ não giữ cache, trạng thái query và config — mọi useQuery/useMutation bên dưới đều cần truy cập nó. Trong Next.js App Router: đặt provider ở root layout nhưng…
- Sự khác biệt giữa isLoading và isFetching trong useQuery?
isLoading = true chỉ lần fetch đầu chưa có cache (show skeleton toàn trang); isFetching = true MỌI KHI đang fetch kể cả background refetch (show subtle indicator). Đây là câu phỏng vấn rất phổ biến. isLoading (hay status === 'pending'): true CHỈ khi fetch…
- Placeholder data và initial data trong React Query khác gì nhau?
initialData được treat như real cached data và ảnh hưởng staleTime; placeholderData là temporary fill UI (isPlaceholderData=true), không persist vào cache — dùng placeholderData: prev = prev để giữ data trang trước khi paginate. Hai option này phục vụ mục đích khác nhau. placeholderData: data…
- select option trong useQuery dùng để làm gì?
select transform data sau fetch trước khi component nhận — cache vẫn lưu raw data; component chỉ re-render khi select result thay đổi; stabilize function với useCallback để tránh re-render không cần thiết. select là transform function chạy sau khi queryFn trả về data, trước…
- Parallel queries và useQueries trong React Query là gì?
Parallel queries là kỹ thuật fetch nhiều API endpoints cùng lúc thay vì tuần tự (waterfall). Cách 1: gọi nhiều useQuery hooks trong cùng component — React Query tự động chạy chúng parallel. Cách 2: useQueries hook nhận mảng query configs, hữu ích khi số…
- Cách cancel queries trong React Query khi component unmount?
queryFn nhận signal (AbortSignal) trong context — truyền signal xuống fetch là bật được huỷ request. Khi component unmount hoặc queryKey đổi, React Query abort signal và trình duyệt huỷ request đang chờ. Huỷ xảy ra trong ba tình huống: - Component unmount trước lúc…
- Query Filters trong React Query là gì? Dùng ở đâu?
- useSuspenseQuery khác gì useQuery? Khi nào dùng?
- persistQueryClient trong React Query dùng để làm gì?
- Mutation side effects: onMutate, onSuccess, onError, onSettled hoạt động ra sao?
- keepPreviousData (placeholderData với identity function) dùng khi nào?
keepPreviousData (v4) đổi thành placeholderData: (prev) = prev ở v5: khi queryKey đổi (trang 1 → trang 2), React Query giữ data trang cũ trên màn hình thay vì xoá đi và hiện loading. Cờ isPlaceholderData cho biết đang hiển thị data cũ. - Phân…
- React Query DevTools là gì? Cách sử dụng?
- Cách xử lý race conditions trong React Query?
- enabled option trong useQuery dùng để làm gì?
enabled: !!dependency là pattern chuẩn cho dependent queries — query không fetch cho đến khi dependency có giá trị; enabled: false + refetch() cho lazy queries triggered by user action. enabled option kiểm soát khi nào query được phép chạy — là boolean hoặc function…
- So sánh React Query với SWR? Khi nào chọn cái nào?
- Redux là gì? Tại sao chúng ta cần sử dụng Redux?
Redux phù hợp cho complex global state cần time-travel debug; RTK là cách dùng Redux 2025. Redux là thư viện quản lý state tập trung cho JavaScript, thường dùng với React. Nó lưu toàn bộ state ứng dụng trong một store duy nhất, giúp dễ…
- Ba nguyên tắc cốt lõi của Redux là gì?
Redux dựa trên ba nguyên tắc: 1. Single source of truth — toàn bộ state nằm trong một store duy nhất. Nhờ vậy data đồng bộ giữa các component, và serialize rồi restore lại rất dễ (lưu state xuống localStorage rồi hydrate khi reload). 2.…
- Action trong Redux là gì? Cấu trúc của một action như thế nào?
Action là plain JavaScript object mô tả sự kiện xảy ra trong ứng dụng, bắt buộc có trường type (string định danh) và thường có payload chứa dữ liệu. Ví dụ: { type: 'cart/addItem', payload: { id: 1, name: 'iPhone', qty: 1 } }. Quy…
- Reducer trong Redux là gì? Cách viết một reducer đúng chuẩn?
Reducer là pure function nhận (state, action) và trả về state mới — không được mutate state trực tiếp mà phải tạo bản sao mới. Ví dụ đúng: case 'ADDTODO': return [...state, action.payload] thay vì state.push(action.payload). Pure function nghĩa là không có side effects, không…
- Store trong Redux là gì? Các phương thức chính của store là gì?
Store là object trung tâm giữ toàn bộ state tree của app, tạo bằng configureStore() (RTK) hoặc createStore() (bản cũ). Ba phương thức chính: - getState() trả về state hiện tại. - dispatch(action) đẩy action qua middleware rồi tới reducer để cập nhật state. -…
- Trong một app React thực tế, bạn phân loại state thành mấy nhóm? Mỗi nhóm dùng công cụ gì?
Chia theo nguồn sở hữu dữ liệu, không chia theo "global hay local". Bốn nhóm hay gặp: - Server state — dữ liệu thuộc về backend, client chỉ giữ bản sao có thể cũ: danh sách đơn hàng, hồ sơ user. Đặc trưng: bất đồng…
- Khi nào một dự án React chưa cần thư viện quản lý state?
Phần lớn dự án vừa và nhỏ chưa cần. Thứ tự leo thang nên theo: 1. useState ngay tại component dùng nó. 2. Lift state up — đưa lên cha chung gần nhất khi hai component anh em cần cùng dữ liệu. 3. Truyền props…
- Context API có thay thế được Redux/Zustand không? Nó thiếu gì so với một state manager?
Context là cơ chế truyền giá trị xuống cây component (dependency injection), không phải state manager. Bản thân nó không lưu state — state vẫn nằm ở useState/useReducer của Provider. Ba thứ nó không có: - Không có selector. Mọi consumer của một context re-render…
- Bộ lọc và phân trang của trang danh sách nên lưu ở đâu? Vì sao nên đẩy lên URL?
Lưu trên URL query param, không phải useState hay store global. State đó thuộc về URL vì nó mô tả "user đang xem cái gì". Lợi ích cụ thể: - Chia sẻ được: copy link gửi đồng nghiệp ra đúng kết quả đã lọc. -…
- Component dùng Zustand bị re-render liên tục (thậm chí lặp vô hạn) khi select nhiều field. Nguyên nhân và cách sửa?
Nguyên nhân: selector trả về object/array mới mỗi lần chạy. Zustand so sánh kết quả selector bằng Object.is, object mới luôn khác object cũ nên component re-render, selector lại chạy, tạo vòng lặp. Ba cách sửa: Cách 3 là chỉ lấy đúng thứ cần: nếu…
- Làm sao đọc/ghi Zustand store từ code ngoài React (interceptor, socket handler)? Và reset store giữa các test bằng cách nào?
Store của Zustand là một object độc lập với React, nên gọi trực tiếp được ở bất kỳ đâu: Lưu ý: getState() chỉ trả về giá trị tại thời điểm gọi, không phản ứng với thay đổi sau đó — đừng dùng trong render, chỉ…
- Trong `createSlice` của Redux Toolkit vì sao viết `state.value += 1` lại không vi phạm nguyên tắc immutability? Có bẫy gì?
Vì RTK dùng Immer bọc reducer. Cái bạn nhận không phải state thật mà là draft proxy: mọi thao tác "mutate" được ghi lại, sau đó Immer tạo ra state mới, chỉ copy những nhánh thực sự đổi (structural sharing). Store vẫn nhận về object…
- Normalize state là gì? Vì sao không nên lưu mảng lồng nhau nguyên trạng từ API vào store?
Normalize là lưu dữ liệu dạng bảng phẳng giống database: mỗi loại entity một map byId, kèm mảng allIds giữ thứ tự — thay vì giữ nguyên cây JSON lồng nhau mà API trả về. Vấn đề của nested: - Một user xuất hiện ở…
- Có nên đưa state của form (giá trị đang gõ) vào Redux/Zustand không? Vì sao?
Mặc định là không. Giá trị đang gõ là state cục bộ, vòng đời bằng vòng đời form, và thay đổi theo từng ký tự. Đưa vào store global gây ba vấn đề: - Mỗi phím gõ dispatch một action → mọi subscriber của store…
- Lưu state vào `localStorage` để giữ giỏ hàng/theme sau khi F5 — vấn đề hydration khi SSR là gì và xử lý ra sao?
Lưu ý: server render không có localStorage — đọc thẳng là ReferenceError, nên phải chặn bằng typeof window và dựng HTML bằng giá trị mặc định; client dựng lại bằng giá trị đã lưu. Hai bản khác nhau → React báo hydration mismatch và có…
- Dự án đã có Redux Toolkit, khi nào vẫn nên viết `createAsyncThunk` và khi nào chuyển hẳn sang RTK Query? Xử lý huỷ request trùng thế nào?
- Vì sao trong Next.js không nên tạo Zustand store ở cấp module? Cách làm đúng là gì?