STATE-MANAGEMENT DOCS

REACT-CONTEXT

createContext
Description: Membuat objek context baru yang bisa dipakai Provider dan Consumer.
Example:
const ThemeContext = React.createContext('light')
Output: Objek ThemeContext
Context.Provider
Description: Menyediakan nilai context ke seluruh anak komponen.
Example:
<ThemeContext.Provider value="dark">
  <App />
</ThemeContext.Provider>
Output: Semua anak mendapat nilai 'dark'
useContext
Description: Hook untuk membaca nilai context di dalam komponen.
Example:
const theme = useContext(ThemeContext)
Output: 'dark'
useReducer + Context
Description: 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
Custom Context Hook
Description: 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()

ZUSTAND

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 }
immer middleware
Description: 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
persist middleware
Description: 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'
devtools middleware
Description: 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
slice pattern
Description: 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

REDUX-TOOLKIT

configureStore
Description: 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
createSlice
Description: 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.actions
Output: counterReducer & actions
createAsyncThunk
Description: 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
useSelector / useDispatch
Description: 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
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 } = api
Output: API slice siap pakai

JOTAI

atom
Description: Membuat unit state terkecil (atom).
Example:
import { atom } from 'jotai'

const countAtom = atom(0)
Output: Atom countAtom
useAtom
Description: Hook untuk membaca dan menulis atom.
Example:
const [count, setCount] = useAtom(countAtom)
Output: Mirip useState, tapi global
derived atom
Description: Atom yang nilainya bergantung pada atom lain.
Example:
const doubleAtom = atom((get) => get(countAtom) * 2)
Output: Nilai otomatis terupdate
writeable derived atom
Description: 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

TANSTACK-QUERY

useQuery
Description: 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 }
useMutation
Description: 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
infiniteQuery
Description: 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
QueryClient & Provider
Description: 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

BEST-PRACTICES

Colocation state
Description: Simpan state sedekat mungkin dengan komponen yang membutuhkan.
Example:
Jika hanya dipakai di satu halaman, jangan simpan di store global
Output: Perform lebih baik
Splitting stores
Description: 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
Memoization
Description: 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