adnenre
#React

Getting Started with React Hooks

Learn how to use React hooks to manage state and side effects in functional components

Hooks are functions that let you “hook into” React state and lifecycle features from functional components. They were introduced in React 16.8 to enable state and other React features without writing a class.

#1 - useState

useState returns an array with two elements: the current state value and a function to update it. The update function triggers a re-render.

import React, { useState } from 'react';

function Counter() {
  // Declare a state variable "count" with initial value 0
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

#2 - useEffect

useEffect lets you perform side effects (data fetching, subscriptions, manual DOM changes) in function components. The second argument is an array of dependencies—the effect runs only when those values change. An empty array [] means the effect runs only once (on mount).

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;

    // Optional cleanup function (componentWillUnmount)
    return () => {
      console.log('Cleanup on unmount or before next effect');
    };
  }, [count]); // Only re-run if count changes

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}*

useEffect lets you perform side effects (data fetching, subscriptions, manual DOM changes) in function components. The second argument is an array of dependencies—the effect runs only when those values change. An empty array [] means the effect runs only once (on mount).

#3 - useContext

useContext accepts a context object and returns the current context value. It eliminates the need for a <Context.Consumer> wrapper.

import React, { useContext } from 'react';

// Create a context with a type
type Theme = 'light' | 'dark';
const ThemeContext = React.createContext<Theme>('dark');

function ThemedButton() {
  // Consume the context value
  const theme = useContext(ThemeContext);

  return (
    <button style={{ background: theme === 'dark' ? '#333' : '#FFF' }}>
      I am styled by theme context!
    </button>
  );
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}

#4 - useReduce

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

import React, { useReducer } from 'react';

// Reducer function
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

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

  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}

#5 - useMemo

useMemo returns a memoized value. It only recomputes when its dependencies change, helping to avoid expensive calculations on every render.

import React, { useMemo, useState } from 'react';

function ExpensiveComputation({ a, b }) {
  const [otherState, setOtherState] = useState(0);

  // Memoize the result of an expensive calculation
  const result = useMemo(() => {
    console.log('Computing...');
    return a * b + otherState; // only recomputed when a, b, or otherState change
  }, [a, b, otherState]);

  return <div>Result: {result}</div>;
}

#6 - useCallback

useCallback returns a memoized version of the callback function. It’s useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.

import React, { useState, useCallback } from 'react';

function Parent() {
  const [count, setCount] = useState(0);

  // Memoized callback function
  const handleClick = useCallback(() => {
    console.log('Button clicked', count);
  }, [count]); // only recreated when count changes

  return <Child onClick={handleClick} />;
}

function Child({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

#7 - useRef

useRef returns a mutable ref object whose .current property is initialized to the passed argument. It persists across renders and can hold any value, most commonly a reference to a DOM element.

import React, { useRef, useEffect } from 'react';

function TextInputWithFocus() {
  const inputRef = useRef(null);

  useEffect(() => {
    // Focus the input element on mount
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} type="text" />;
}

#8 - custom hooks

You can create your own hooks to reuse stateful logic between components.

import { useState, useEffect } from 'react';

// Custom hook: useWindowWidth
function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return width;
}

// Usage in a component
function MyComponent() {
  const width = useWindowWidth();
  return <div>Window width: {width}px</div>;
}

Custom hooks let you extract component logic into reusable functions. Their names should start with use to follow the Rules of Hooks.

Rules of Hooks

  • Only call hooks at the top level (not inside loops, conditions, or nested functions).

  • Only call hooks from React function components or custom hooks.

Following these rules ensures that state is preserved correctly between renders.

Share this post