STATE-MANAGEMENT DOCS
REACT-CONTEXT
Name
Description
Example
Output
createContextDescription: Membuat objek context baru yang bisa dipakai Provider dan Consumer.
Example:
const ThemeContext = React.createContext('light')Output: Objek ThemeContext
createContextMembuat objek context baru yang bisa dipakai Provider dan Consumer.
const ThemeContext = React.createContext('light')Objek ThemeContext
Context.ProviderDescription: Menyediakan nilai context ke seluruh anak komponen.
Example:
<ThemeContext.Provider value="dark"> <App /> </ThemeContext.Provider>
Output: Semua anak mendapat nilai 'dark'
Context.ProviderMenyediakan nilai context ke seluruh anak komponen.
<ThemeContext.Provider value="dark"> <App /> </ThemeContext.Provider>
Semua anak mendapat nilai 'dark'
useContextDescription: Hook untuk membaca nilai context di dalam komponen.
Example:
const theme = useContext(ThemeContext)
Output: 'dark'
useContextHook untuk membaca nilai context di dalam komponen.
const theme = useContext(ThemeContext)
'dark'
useReducer + ContextDescription: Menggabungkan useReducer dengan Context untuk state management sederhana.
Example:
const [state, dispatch] = useReducer(reducer, initialState)
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{children}Output: State & dispatch tersedia global
useReducer + ContextMenggabungkan useReducer dengan Context untuk state management sederhana.
const [state, dispatch] = useReducer(reducer, initialState)
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{children}State & dispatch tersedia global
Custom Context HookDescription: Membungkus useContext dalam custom hook untuk kenyamanan dan keamanan tipe.
Example:
function useAppState() {
const context = useContext(AppStateContext)
if (!context) throw new Error('Harus di dalam Provider')
return context
}Output: useAppState()
Custom Context HookMembungkus useContext dalam custom hook untuk kenyamanan dan keamanan tipe.
function useAppState() {
const context = useContext(AppStateContext)
if (!context) throw new Error('Harus di dalam Provider')
return context
}useAppState()
ZUSTAND
Name
Description
Example
Output
create (store sederhana)Description: Membuat store Zustand dengan state dan action.
Example:
import { create } from 'zustand'
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
reset: () => set({ count: 0 })
}))Output: useStore() → { count, increment, reset }
create (store sederhana)Membuat store Zustand dengan state dan action.
import { create } from 'zustand'
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
reset: () => set({ count: 0 })
}))useStore() → { count, increment, reset }
immer middlewareDescription: Menggunakan Immer untuk mutasi state yang lebih natural.
Example:
import { immer } from 'zustand/middleware/immer'
const useStore = create(immer((set) => ({
user: { name: '', age: 0 },
setUserName: (name) => set((state) => { state.user.name = name })
})))Output: State bisa dimutasi langsung
immer middlewareMenggunakan Immer untuk mutasi state yang lebih natural.
import { immer } from 'zustand/middleware/immer'
const useStore = create(immer((set) => ({
user: { name: '', age: 0 },
setUserName: (name) => set((state) => { state.user.name = name })
})))State bisa dimutasi langsung
persist middlewareDescription: Menyimpan state ke localStorage / sessionStorage secara otomatis.
Example:
import { persist } from 'zustand/middleware'
const useStore = create(persist((set) => ({
theme: 'light',
setTheme: (theme) => set({ theme })
}), { name: 'app-theme' }))Output: State disimpan di localStorage 'app-theme'
persist middlewareMenyimpan state ke localStorage / sessionStorage secara otomatis.
import { persist } from 'zustand/middleware'
const useStore = create(persist((set) => ({
theme: 'light',
setTheme: (theme) => set({ theme })
}), { name: 'app-theme' }))State disimpan di localStorage 'app-theme'
devtools middlewareDescription: Mengaktifkan Redux DevTools untuk debugging Zustand.
Example:
import { devtools } from 'zustand/middleware'
const useStore = create(devtools((set) => ({
count: 0,
increase: () => set({ count: c => c + 1 }, false, 'increase')
})))Output: DevTools mendeteksi store
devtools middlewareMengaktifkan Redux DevTools untuk debugging Zustand.
import { devtools } from 'zustand/middleware'
const useStore = create(devtools((set) => ({
count: 0,
increase: () => set({ count: c => c + 1 }, false, 'increase')
})))DevTools mendeteksi store
slice patternDescription: Membagi store menjadi beberapa slice (module) untuk kode yang lebih rapi.
Example:
const createUserSlice = (set) => ({ user: null, setUser: (user) => set({ user }) })
const createCounterSlice = (set) => ({ count: 0, inc: () => set(s => ({ count: s.count + 1 })) })
const useStore = create((...a) => ({
...createUserSlice(...a),
...createCounterSlice(...a)
}))Output: Store gabungan
slice patternMembagi store menjadi beberapa slice (module) untuk kode yang lebih rapi.
const createUserSlice = (set) => ({ user: null, setUser: (user) => set({ user }) })
const createCounterSlice = (set) => ({ count: 0, inc: () => set(s => ({ count: s.count + 1 })) })
const useStore = create((...a) => ({
...createUserSlice(...a),
...createCounterSlice(...a)
}))Store gabungan
REDUX-TOOLKIT
Name
Description
Example
Output
configureStoreDescription: Membuat store Redux dengan konfigurasi default yang baik.
Example:
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
export const store = configureStore({
reducer: { counter: counterReducer }
})Output: Store Redux
configureStoreMembuat store Redux dengan konfigurasi default yang baik.
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
export const store = configureStore({
reducer: { counter: counterReducer }
})Store Redux
createSliceDescription: Membuat reducer dan action creator secara otomatis.
Example:
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1 },
decrement: (state) => { state.value -= 1 },
incrementBy: (state, action) => { state.value += action.payload }
}
})
export const { increment, decrement, incrementBy } = counterSlice.actionsOutput: counterReducer & actions
createSliceMembuat reducer dan action creator secara otomatis.
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1 },
decrement: (state) => { state.value -= 1 },
incrementBy: (state, action) => { state.value += action.payload }
}
})
export const { increment, decrement, incrementBy } = counterSlice.actionscounterReducer & actions
createAsyncThunkDescription: Membuat action asinkron yang otomatis dispatch pending/fulfilled/rejected.
Example:
const fetchUser = createAsyncThunk('user/fetch', async (userId) => {
const response = await fetch(`/api/users/${userId}`)
return response.json()
})
// di slice:
extraReducers: (builder) => {
builder.addCase(fetchUser.fulfilled, (state, action) => { state.user = action.payload })
}Output: Async action fetchUser
createAsyncThunkMembuat action asinkron yang otomatis dispatch pending/fulfilled/rejected.
const fetchUser = createAsyncThunk('user/fetch', async (userId) => {
const response = await fetch(`/api/users/${userId}`)
return response.json()
})
// di slice:
extraReducers: (builder) => {
builder.addCase(fetchUser.fulfilled, (state, action) => { state.user = action.payload })
}Async action fetchUser
useSelector / useDispatchDescription: Hook React-Redux untuk membaca state dan dispatch action.
Example:
import { useSelector, useDispatch } from 'react-redux'
const count = useSelector(state => state.counter.value)
const dispatch = useDispatch()
dispatch(increment())Output: Membaca/mengubah state Redux
useSelector / useDispatchHook React-Redux untuk membaca state dan dispatch action.
import { useSelector, useDispatch } from 'react-redux'
const count = useSelector(state => state.counter.value)
const dispatch = useDispatch()
dispatch(increment())Membaca/mengubah state Redux
RTK Query (createApi)Description: Membuat data fetching & caching layer yang powerful.
Example:
const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
endpoints: (builder) => ({
getPosts: builder.query({ query: () => '/posts' }),
addPost: builder.mutation({ query: (body) => ({ url: '/posts', method: 'POST', body }) })
})
})
export const { useGetPostsQuery, useAddPostMutation } = apiOutput: API slice siap pakai
RTK Query (createApi)Membuat data fetching & caching layer yang powerful.
const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
endpoints: (builder) => ({
getPosts: builder.query({ query: () => '/posts' }),
addPost: builder.mutation({ query: (body) => ({ url: '/posts', method: 'POST', body }) })
})
})
export const { useGetPostsQuery, useAddPostMutation } = apiAPI slice siap pakai
JOTAI
Name
Description
Example
Output
atomDescription: Membuat unit state terkecil (atom).
Example:
import { atom } from 'jotai'
const countAtom = atom(0)Output: Atom countAtom
atomMembuat unit state terkecil (atom).
import { atom } from 'jotai'
const countAtom = atom(0)Atom countAtom
useAtomDescription: Hook untuk membaca dan menulis atom.
Example:
const [count, setCount] = useAtom(countAtom)
Output: Mirip useState, tapi global
useAtomHook untuk membaca dan menulis atom.
const [count, setCount] = useAtom(countAtom)
Mirip useState, tapi global
derived atomDescription: Atom yang nilainya bergantung pada atom lain.
Example:
const doubleAtom = atom((get) => get(countAtom) * 2)
Output: Nilai otomatis terupdate
derived atomAtom yang nilainya bergantung pada atom lain.
const doubleAtom = atom((get) => get(countAtom) * 2)
Nilai otomatis terupdate
writeable derived atomDescription: Derived atom yang bisa dibaca dan ditulis (computed + setter).
Example:
const priceAtom = atom(100) const discountAtom = atom(10) const finalPriceAtom = atom( (get) => get(priceAtom) - get(discountAtom), (get, set, newPrice) => set(priceAtom, newPrice + get(discountAtom)) )
Output: Atom dua arah
writeable derived atomDerived atom yang bisa dibaca dan ditulis (computed + setter).
const priceAtom = atom(100) const discountAtom = atom(10) const finalPriceAtom = atom( (get) => get(priceAtom) - get(discountAtom), (get, set, newPrice) => set(priceAtom, newPrice + get(discountAtom)) )
Atom dua arah
TANSTACK-QUERY
Name
Description
Example
Output
useQueryDescription: Hook untuk fetching data otomatis dengan caching, refetch, dll.
Example:
const { data, isLoading, error } = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/api/todos').then(res => res.json())
})Output: { data: [...], isLoading: false }
useQueryHook untuk fetching data otomatis dengan caching, refetch, dll.
const { data, isLoading, error } = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/api/todos').then(res => res.json())
}){ data: [...], isLoading: false }
useMutationDescription: Hook untuk operasi mutasi data (POST, PUT, DELETE).
Example:
const mutation = useMutation({
mutationFn: (newTodo) => fetch('/api/todos', { method: 'POST', body: JSON.stringify(newTodo) }),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] })
})
mutation.mutate({ title: 'Belajar' })Output: Data terkirim, cache di-refresh
useMutationHook untuk operasi mutasi data (POST, PUT, DELETE).
const mutation = useMutation({
mutationFn: (newTodo) => fetch('/api/todos', { method: 'POST', body: JSON.stringify(newTodo) }),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] })
})
mutation.mutate({ title: 'Belajar' })Data terkirim, cache di-refresh
infiniteQueryDescription: Mendukung infinite scroll / load more dengan cursor pagination.
Example:
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam = 0 }) => fetch(`/api/projects?cursor=${pageParam}`),
getNextPageParam: (lastPage) => lastPage.nextCursor
})Output: Data halaman-per-halaman
infiniteQueryMendukung infinite scroll / load more dengan cursor pagination.
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam = 0 }) => fetch(`/api/projects?cursor=${pageParam}`),
getNextPageParam: (lastPage) => lastPage.nextCursor
})Data halaman-per-halaman
QueryClient & ProviderDescription: Setup QueryClient untuk menyediakan cache ke seluruh aplikasi.
Example:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>Output: TanStack Query siap
QueryClient & ProviderSetup QueryClient untuk menyediakan cache ke seluruh aplikasi.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>TanStack Query siap
BEST-PRACTICES
Name
Description
Example
Output
Colocation stateDescription: Simpan state sedekat mungkin dengan komponen yang membutuhkan.
Example:
Jika hanya dipakai di satu halaman, jangan simpan di store global
Output: Perform lebih baik
Colocation stateSimpan state sedekat mungkin dengan komponen yang membutuhkan.
Jika hanya dipakai di satu halaman, jangan simpan di store global
Perform lebih baik
Splitting storesDescription: Pisah store berdasarkan domain (userStore, cartStore) untuk mencegah re-render berlebih.
Example:
Zustand: banyak store kecil Redux: satu store, banyak slice
Output: Re-render lebih sedikit
Splitting storesPisah store berdasarkan domain (userStore, cartStore) untuk mencegah re-render berlebih.
Zustand: banyak store kecil Redux: satu store, banyak slice
Re-render lebih sedikit
MemoizationDescription: Gunakan selector yang tepat agar komponen hanya render jika data yang dibutuhkan berubah.
Example:
const count = useStore(state => state.count)
Output: Hanya render ulang saat count berubah
MemoizationGunakan selector yang tepat agar komponen hanya render jika data yang dibutuhkan berubah.
const count = useStore(state => state.count)
Hanya render ulang saat count berubah