- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDeviceList
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMediaStream
- useMemory
- useNetwork
- useNotification
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
- useVibrate
- useVirtualKeyboard
- useWakeLock
- useWebSocket
- useWebWorker
- useWebWorkerCallback
- useBoolean
- useControllableState
- useCookie
- useCookies
- useCounter
- useCycleList
- useDefault
- useDisclosure
- useField
- useForm
- useHash
- useList
- useLocalStorage
- useMap
- useMask
- useMergedRef
- useObject
- useOffsetPagination
- useQueue
- useRafState
- useRefState
- useSessionStorage
- useSet
- useStateHistory
- useStep
- useStorage
- useToggle
- useUrlSearchParam
- useUrlSearchParams
- useValidatedState
- useWizard
- useDeviceMotion
- useDeviceOrientation
- useHotkeys
- useIdle
- useInfiniteScroll
- useIntersectionObserver
- useKeyboard
- useKeyPress
- useKeysPressed
- useMouse
- useMutationObserver
- useOrientation
- usePageLeave
- useParallax
- usePerformanceObserver
- useResizeObserver
- useScroll
- useScrollIntoView
- useScrollTo
- useSwipe
- useTextSelection
- useVisibility
- useWindowEvent
- useWindowFocus
- useWindowScroll
- useWindowSize
Extract feature logic into a hook
Move complex feature logic out of components into one hook, and group its return.
When a component owns complex feature logic — a form, a couple of modals, a mutation, some persisted state — the file turns into a tangle of useState, handlers, and effects with the actual UI buried at the bottom. The fix isn't "make the file shorter." It's to move that logic into one hook that represents the feature, with a public contract the component reads. The component becomes UI composition; the hook becomes the feature controller.
The problem: a component doing everything
import { useState } from 'react';
import { useDisclosure, useMutation } from '@siberiacancode/reactuse';
const CreateDeckPage = () => {
const [createDeck, createDeckState] = useMutation(createDeckRequest);
const editModal = useDisclosure();
const [selectedDeck, setSelectedDeck] = useState<Deck>();
const onEdit = (deck: Deck) => {
setSelectedDeck(deck);
editModal.open();
};
// ...more handlers, more state, and only then the JSX
return <CreateDeckView /* a dozen loose props */ />;
};Everything works, but the component is a bag of unrelated values. Add validation, persistence, and a second modal and it only gets worse.
The fix: one feature hook, grouped return
Move it into a hook named after the feature, and group the return by how the UI consumes it rather than returning one flat object:
import { useState } from 'react';
import { useDisclosure, useForm, useMutation } from '@siberiacancode/reactuse';
interface UseCreateDeckParams {
initialName: string;
}
export const useCreateDeck = ({ initialName }: UseCreateDeckParams) => {
const createDeckMutation = useMutation(createDeckRequest);
const editModal = useDisclosure();
const [selectedDeck, setSelectedDeck] = useState<Deck>();
const createDeckForm = useForm<CreateDeckFormValues>({
defaultValues: { name: initialName }
});
const onSubmit = createDeckForm.handleSubmit((values) => createDeckMutation.mutate(values));
const onEdit = (deck: Deck) => {
setSelectedDeck(deck);
editModal.open();
};
return {
form: createDeckForm,
state: {
selectedDeck,
loading: createDeckMutation.isLoading
},
functions: {
onSubmit,
onEdit
},
features: {
editModal
}
};
};Now the component reads one clear model instead of a dozen loose props — form, state, functions, features — each with an obvious purpose:
const { state, functions, form, features } = useCreateDeck(props);Whatever renders it receives this shape directly — no need to trace where each value came from.
The four buckets
Use these as your default return vocabulary — they map to how the component uses each thing, not to what type it is:
form— the form object or form-specific API.state— values the UI renders.functions— commands and event handlers the UI calls.features— nested feature objects: modals, drawers, popovers, uploaders, child controllers.
Add a bucket (refs, for example) when the domain needs it — but keep it semantic. Don't invent a group just to avoid naming a value, and don't dump everything into one flat object.
Naming
Name the hook after the component or feature it powers, and name its params type Use…Params:
CreateDeckPage→useCreateDeck→UseCreateDeckParamsCheckoutFlow→useCheckoutFlow→UseCheckoutFlowParams
Keep the params type next to the hook, and prefer interface when the object will grow with the feature.
When to extract — and when to split
This isn't only about browser subscriptions like scroll or mouse. The bigger win is business logic: a form plus its validation and submit flow, a mutation plus the navigation after it succeeds, selected-entity and edit-mode state, persisted values a feature depends on. These belong together as one feature scenario, behind one hook.
So extract when the hook is a real unit of behavior with a clear contract — not just to shorten a file. And when the return shape grows, split by feature boundary first: pull deck editing into its own useDeckEditing only once it's independently meaningful, not merely because the parent hook got long.
Browse the full hook list and the reactuse skills to compose your next feature hook.