Adhere strictly to React hooks rules and best practices to ensure your components behave correctly and predictably. Common issues include:
// INCORRECT: Missing snap.enforceExactCount and error.code in dependencies
useEffect(() => {
if (isError && snap.enforceExactCount && error.code === 408) {
// ...
}
}, [isError]);
// CORRECT: Include all dependencies
useEffect(() => {
if (isError && snap.enforceExactCount && error.code === 408) {
// ...
}
}, [isError, snap.enforceExactCount, error.code]);
// ALTERNATIVE: Use useLatest for values you want to read but not trigger re-runs
const latestSnap = useLatest(snap);
const latestError = useLatest(error);
useEffect(() => {
if (isError && latestSnap.current.enforceExactCount && latestError.current.code === 408) {
// ...
}
}, [isError]);
// INCORRECT: Conditionally calling a hook breaks the rules of hooks
const { hasAcceptedConsent } = IS_PLATFORM ? useConsentToast() : { hasAcceptedConsent: true }
// CORRECT: Use a parameter to conditionally enable the hook's behavior
const { hasAcceptedConsent } = useConsentToast({ enabled: IS_PLATFORM })
// INCORRECT: Inline function breaks memoization on each render
<MemoizedComponent
onResults={(props) => snap.updateMessage({ id: message.id, ...props })}
/>
// CORRECT: Preserve memoization with useCallback
const handleResults = useCallback((props) => {
snap.updateMessage({ id: message.id, ...props })
}, [message.id, snap])
<MemoizedComponent onResults={handleResults} />
Remember that hook calls must be at the top level of your component to ensure they’re called in the same order on each render.
Enter the URL of a public GitHub repository