Back to all reviewers

Hook and state correctness

langfuse/langfuse
Based on 6 comments
TSX

Ensure React hooks and state updates follow best practices to prevent subtle bugs: 1. **Call hooks unconditionally** at the top level of your component or custom hook - never inside conditionals, loops, or nested functions:

React TSX

Reviewer Prompt

Ensure React hooks and state updates follow best practices to prevent subtle bugs:

  1. Call hooks unconditionally at the top level of your component or custom hook - never inside conditionals, loops, or nested functions:
// INCORRECT
function Component() {
  const someCondition = true;
  if (someCondition) {
    useEffect(() => {/* effect */}, []);  // Violation of hook rules
  }
  
  const memoizedData = useMemo(() => {
    const { getNavigationPath } = useTracePeekNavigation();  // Hooks inside other hooks
    return { getNavigationPath };
  }, []);
}

// CORRECT
function Component() {
  const { getNavigationPath } = useTracePeekNavigation();
  const memoizedData = useMemo(() => {
    return { getNavigationPath };  // Use hook result inside memo
  }, [getNavigationPath]);
}
  1. Include all dependencies in hook dependency arrays (useEffect, useMemo, useCallback) to avoid stale closures:
// INCORRECT - missing 'canEdit' dependency
const handleWidthChange = useCallback(
  (containerWidth) => {
    setEditable(canEdit && cols === 12);  // Uses canEdit but missing from deps
  },
  [cols]
);

// CORRECT
const handleWidthChange = useCallback(
  (containerWidth) => {
    setEditable(canEdit && cols === 12);
  },
  [cols, canEdit]  // All dependencies listed
);
  1. Use proper state update patterns to prevent stale state:
// INCORRECT - may use stale state
setOpen((value) => {
  const newValue = typeof value === "function" ? value(open) : value;
  // Using 'open' can be stale
});

// CORRECT - always uses fresh state
setOpen((currentOpen) => {
  const newValue = typeof value === "function" ? value(currentOpen) : value;
  return newValue;
});
  1. Use reactive state access methods for form libraries and other state:
// INCORRECT - not reactive
disabled={isInProgress.data || !form.getValues().targetId}

// CORRECT - reacts to field changes
disabled={isInProgress.data || !form.watch('targetId')}

Following these patterns helps prevent difficult-to-debug issues like inconsistent renders, stale closures, and unpredictable component behavior.

6
Comments Analyzed
TSX
Primary Language
React
Category

Source Discussions