useHooks - Mastering React Built-in Hooks


React provides a set of built-in Hooks that enable you to manage state, handle side effects, optimize performance, and share logic across components. This guide explores these Hooks, offering syntax explanations, examples, and best practices.

useState

useState is a React Hook that lets you add a state variable to your functional components.

Syntax

const [state, setState] = useState(initialState);

Key Features and Usage

  1. Adding State to a Component

    const [age, setAge] = useState(28);
    const [name, setName] = useState('Taylor');
    const [todos, setTodos] = useState(() => createTodos());
    
  2. Updating State Based on Previous State

    setAge(prevAge => prevAge + 1);
    
  3. Updating Objects and Arrays in State Always create a new copy of objects or arrays before updating them:

    setTodos(prevTodos => [...prevTodos, newTodo]);
    
  4. Avoiding Recreating Initial State Use an initializer function for performance optimization:

    const [count, setCount] = useState(() => computeInitialCount());
    

Troubleshooting

Example

const [name, setName] = useState('Edward');

function handleClick() {
  setName('Taylor');
  setAge(a => a + 1);
}

useReducer

useReducer is a React Hook that provides a more structured approach to managing state, especially for complex state logic.

Syntax

const [state, dispatch] = useReducer(reducer, initialState);

Examples

Example: Simple Counter

function reducer(state, action) {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    default: return state;
  }
}

const [state, dispatch] = useReducer(reducer, { count: 0 });

function increment() {
  dispatch({ type: 'increment' });
}

Additional Examples

  1. Managing Forms

    function reducer(state, action) {
      switch (action.type) {
        case 'changed_name': return { ...state, name: action.nextName };
        case 'incremented_age': return { ...state, age: state.age + 1 };
        default: return state;
      }
    }
    
  2. Task Management

    function tasksReducer(tasks, action) {
      switch (action.type) {
        case 'added': return [...tasks, { id: action.id, text: action.text }];
        case 'deleted': return tasks.filter(task => task.id !== action.id);
        default: throw new Error('Unknown action');
      }
    }
    

Key Features

useContext

useContext simplifies accessing and subscribing to context values.

Syntax

const value = useContext(SomeContext);

Usage

Avoids "prop drilling" by sharing values directly.

Examples

  1. Theme Context
    const ThemeContext = React.createContext('light');
    
    function Button() {
      const theme = useContext(ThemeContext);
      return <button className={`btn-${theme}`}>Click Me</button>;
    }
    
  2. Combining Context with State
    function MyApp() {
      const [theme, setTheme] = useState('light');
      return (
        <ThemeContext.Provider value={theme}>
          <ChildComponent />
        </ThemeContext.Provider>
      );
    }
    

Caveats

useRef

The useRef hook manages mutable references or directly interacts with the DOM.

Syntax

const ref = useRef(initialValue);

Key Concepts

Common Use Cases

  1. Referencing DOM Elements
    const inputRef = useRef(null);
    
    function focusInput() {
      inputRef.current.focus();
    }
    
  2. Managing Timers
    const intervalRef = useRef(null);
    

useEffect

The useEffect hook synchronizes components with external systems.

Syntax

useEffect(setup, dependencies);

How It Works

Common Use Cases

  1. Global Event Listeners
    useEffect(() => {
      const handleResize = () => console.log(window.innerWidth);
      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }, []);
    
  2. API Calls
    useEffect(() => {
      fetchData();
    }, []);
    

useMemo

useMemo optimizes performance by caching calculations.

Syntax

const memoizedValue = useMemo(calculateValue, dependencies);

Examples

  1. Filtering Todos
    const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
    

useCallback

useCallback optimizes function reuse between renders.

Syntax

const cachedFn = useCallback(fn, dependencies);

Key Use Cases

  1. Skipping Component Re-Renders
    const handleSubmit = useCallback((orderDetails) => {
      post('/buy', { orderDetails });
    }, []);
    

Custom Hooks

Custom hooks encapsulate reusable logic.

Example: Tracking Online/Offline Status

useOnlineStatus Hook:

function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() => {
    const handleOnline = () => setIsOnline(true);
    window.addEventListener('online', handleOnline);
    return () => window.removeEventListener('online', handleOnline);
  }, []);
  return isOnline;
}

Simplified Components:

function StatusBar() {
  const isOnline = useOnlineStatus();
  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
}