Bird
Raised Fist0
Reactframework~8 mins

Reusing logic with hooks in React - Performance & Optimization

Choose your learning style10 modes available
Performance: Reusing logic with hooks
MEDIUM IMPACT
This affects interaction responsiveness and rendering efficiency by reducing unnecessary component updates and re-renders.
Sharing stateful logic across multiple components
React
function useCounter() {
  const [count, setCount] = React.useState(0);
  const increment = React.useCallback(() => setCount(c => c + 1), []);
  return { count, increment };
}

function ComponentA() {
  const { count, increment } = useCounter();
  return <button onClick={increment}>Count: {count}</button>;
}

function ComponentB() {
  const { count, increment } = useCounter();
  return <button onClick={increment}>Count: {count}</button>;
}
Extracting logic into a custom hook avoids code duplication and ensures consistent state management with memoized callbacks.
📈 Performance GainSaves bundle size and improves INP by reducing unnecessary re-renders and re-creating functions.
Sharing stateful logic across multiple components
React
function ComponentA() {
  const [count, setCount] = React.useState(0);
  const increment = () => setCount(count + 1);
  return <button onClick={increment}>Count: {count}</button>;
}

function ComponentB() {
  const [count, setCount] = React.useState(0);
  const increment = () => setCount(count + 1);
  return <button onClick={increment}>Count: {count}</button>;
}
Duplicating state logic in multiple components causes repeated code and separate state management, increasing bundle size and potential bugs.
📉 Performance CostAdds extra bundle size and causes independent re-renders for each component.
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
Duplicated state logic in componentsMultiple independent statesMultiple reflows per component updateHigher paint cost due to repeated renders[X] Bad
Custom hook with memoized callbacksSingle state logic reusedSingle reflow per state updateLower paint cost due to fewer renders[OK] Good
Rendering Pipeline
Custom hooks encapsulate state and logic, so React only re-renders components when state changes. Memoizing callbacks reduces layout recalculations and paint.
→JavaScript Execution
→Reconciliation
→Layout
→Paint
⚠️ BottleneckReconciliation stage due to unnecessary re-renders if hooks are not optimized
Core Web Vital Affected
INP
This affects interaction responsiveness and rendering efficiency by reducing unnecessary component updates and re-renders.
Optimization Tips
1Extract reusable logic into custom hooks to avoid code duplication.
2Use React.useCallback inside hooks to memoize functions and prevent unnecessary re-renders.
3Monitor component re-renders with React DevTools Profiler to ensure hooks improve performance.
Performance Quiz - 3 Questions
Test your performance knowledge
What is a main performance benefit of using custom hooks to reuse logic in React?
ATriggers more layout recalculations
BIncreases bundle size by adding more code
CReduces code duplication and prevents unnecessary re-renders
DBlocks rendering until all hooks finish
DevTools: React DevTools and Performance panel
How to check: Open React DevTools Profiler, record interactions, and observe component re-render counts and durations. Use Performance panel to check layout and paint times.
What to look for: Look for fewer component re-renders and shorter interaction times indicating better INP and less layout thrashing.

Practice

(1/5)
1. What is the main purpose of creating a custom hook in React?
easy
A. To create new HTML elements
B. To reuse stateful logic across multiple components
C. To style components with CSS
D. To replace React components entirely

Solution

  1. Step 1: Understand what hooks do

    Hooks let you use React features like state and effects inside functions.
  2. Step 2: Identify the role of custom hooks

    Custom hooks let you reuse this logic in many components without repeating code.
  3. Final Answer:

    To reuse stateful logic across multiple components -> Option B
  4. Quick Check:

    Custom hooks = reuse logic [OK]
Hint: Custom hooks start with 'use' and share logic [OK]
Common Mistakes:
  • Thinking hooks create UI elements
  • Confusing hooks with styling tools
  • Believing hooks replace components
2. Which of the following is the correct way to define a custom hook in React?
easy
A. function useCounter() { const [count, setCount] = useState(0); return [count, setCount]; }
B. function counterHook() { const [count, setCount] = useState(0); return [count, setCount]; }
C. function UseCounter() { const [count, setCount] = useState(0); return [count, setCount]; }
D. function counter() { const [count, setCount] = useState(0); return [count, setCount]; }

Solution

  1. Step 1: Recall naming rules for custom hooks

    Custom hooks must start with 'use' to follow React conventions and enable linting.
  2. Step 2: Check function names

    Only function useCounter() { const [count, setCount] = useState(0); return [count, setCount]; } starts with 'use' and uses camelCase correctly.
  3. Final Answer:

    function useCounter() { const [count, setCount] = useState(0); return [count, setCount]; } -> Option A
  4. Quick Check:

    Custom hook names start with 'use' [OK]
Hint: Custom hooks always start with 'use' prefix [OK]
Common Mistakes:
  • Not starting function name with 'use'
  • Using uppercase first letter in hook name
  • Naming hooks like regular functions
3. Given this custom hook code, what will be logged when ExampleComponent renders?
function useToggle(initial) {
  const [on, setOn] = React.useState(initial);
  const toggle = () => setOn(!on);
  return [on, toggle];
}

function ExampleComponent() {
  const [isOn, toggle] = useToggle(false);
  React.useEffect(() => {
    console.log(isOn);
  }, [isOn]);
  return Toggle;
}
medium
A. undefined on first render, then false after button click
B. true on first render, then false after button click
C. No output because console.log is inside useEffect
D. false on first render, then true after button click

Solution

  1. Step 1: Analyze initial state in useToggle

    The hook starts with initial = false, so isOn is false initially.
  2. Step 2: Understand useEffect logging

    useEffect logs isOn after render; initially logs false, after toggle logs true.
  3. Final Answer:

    false on first render, then true after button click -> Option D
  4. Quick Check:

    Initial state false, toggles true [OK]
Hint: Initial state logs first, toggle changes it [OK]
Common Mistakes:
  • Assuming initial state is true
  • Thinking console.log won't run inside useEffect
  • Confusing toggle function behavior
4. What is wrong with this custom hook code?
function useCounter() {
  const [count, setCount] = React.useState(0);
  function increment() {
    count = count + 1;
  }
  return { count, increment };
}
medium
A. Directly modifying count variable instead of using setCount
B. Missing React import for useState
C. increment function should return count
D. Custom hook name should not start with 'use'

Solution

  1. Step 1: Check how state is updated

    State variables like count must be updated via setCount, not by direct assignment.
  2. Step 2: Identify the error in increment

    increment tries to assign count = count + 1, which does not update React state.
  3. Final Answer:

    Directly modifying count variable instead of using setCount -> Option A
  4. Quick Check:

    State updates need setCount [OK]
Hint: Always use setState to update state, never assign directly [OK]
Common Mistakes:
  • Trying to assign state variable directly
  • Forgetting to call setCount
  • Confusing variable assignment with state update
5. You want to create a custom hook useFetch that fetches data from a URL and returns loading state, data, and error. Which approach correctly reuses logic and handles updates safely?
function useFetch(url) {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    setLoading(true);
    fetch(url)
      .then(res => res.json())
      .then(json => {
        setData(json);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
}
hard
A. This hook will cause infinite loops because setState is inside useEffect
B. This hook should not use useEffect for fetching data
C. This hook correctly reuses fetch logic and updates state on URL change
D. This hook must return an array, not an object

Solution

  1. Step 1: Check useEffect dependency

    useEffect runs when URL changes, so fetch updates correctly.
  2. Step 2: Verify state updates inside fetch

    State updates happen after fetch resolves or errors, no infinite loops occur.
  3. Step 3: Confirm return value format

    Returning an object with data, loading, error is a common pattern and valid.
  4. Final Answer:

    This hook correctly reuses fetch logic and updates state on URL change -> Option C
  5. Quick Check:

    useEffect fetches on URL change, updates state [OK]
Hint: useEffect with URL dependency safely fetches data [OK]
Common Mistakes:
  • Thinking setState inside useEffect causes loops
  • Not using useEffect for side effects
  • Confusing return types of hooks
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard