Blog Highlights

Explore my latest thoughts, insights, and innovations in technology, AI, development, and security. Dive into comprehensive guides and analyses.

Back to all posts

React Hooks

May 29, 2023 by Rakesh Udutha Read Time: 4 min readReact

React Hooks are a feature introduced in React 16.8 that allow developer to use state and other React features without writing class components. Hooks provide a more concise and functional way of managing component state and lifecycle events.

React provides several built-in hooks that serve different purpose. Here are some commonly used React Hooks:

  • useState: Allow you to add state to functional components. It return a state variable and a function to update that variable.
import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default Counter;
  • useEffect: Enables performing side effects in functional components, such as fetching data, subscribing to events, or manipulating the DOM. It replaces lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.
import React, { useEffect, useState } from 'react';

const UserList = () => {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    // Fetch users from API or perform any other side effect
    const fetchUsers = async () => {
      try {
        const response = await fetch('https://api.example.com/users');
        const data = await response.json();
        setUsers(data);
      } catch (error) {
        console.error('Error fetching users:', error);
      }
    };

    fetchUsers(); // Call the fetchUsers function when the component mounts

    // Clean up function
    return () => {
      // Perform any necessary cleanup here
    };
  }, []); // The empty dependency array ensures that the effect runs only once

  return (
    <div>
      <h2>User List</h2>
      {users.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  );
};

export default UserList;
  • useContext: Allows you to access the value of a context in a functional component. It is used in conjunction with the context API to share data across components without prop drilling.
import React, { useContext } from 'react';

// Create a context
const UserContext = React.createContext();

// Parent component that provides the context value
const UserProvider = ({ children }) => {
  const user = {
    name: 'John Doe',
    email: 'johndoe@example.com',
  };

  return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
};

// Child component that consumes the context value
const UserProfile = () => {
  const user = useContext(UserContext);

  return (
    <div>
      <h2>User Profile</h2>
      <p>Name: {user.name}</p>
      <p>Email: {user.email}</p>
    </div>
  );
};

// Parent component that uses the UserProvider and UserProfile components
const App = () => {
  return (
    <UserProvider>
      <UserProfile />
    </UserProvider>
  );
};

export default App;
  • useReducer: Provides an alternative to useState when the state logic is complex and involves multiple values and actions. It follows the Redux pattern of having a state and a reducer function to handle state updates.
import React, { useReducer } from 'react';

// Initial state
const initialState = {
  count: 0,
};

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

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

  const increment = () => {
    dispatch({ type: 'increment' });
  };

  const decrement = () => {
    dispatch({ type: 'decrement' });
  };

  const reset = () => {
    dispatch({ type: 'reset' });
  };

  return (
    <div>
      <h2>Count: {state.count}</h2>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
};

export default Counter;
  • useRef: Returns a mutable ref object that can hold a value. It can be used to reference DOM elements, store previous values, or persist values across renders.
import React, { useRef } from 'react';

const InputComponent = () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};

export default InputComponent;
  • useMemo: Memoizes a value, preventing expensive computations on every render. It allows you to optimize performance by caching the result of a function or the value of a variable until its dependencies change.
import React, { useMemo } from 'react';

const ExpensiveComponent = ({ data }) => {
  // Perform expensive calculations or operations
  const expensiveResult = useMemo(() => {
    // Perform calculations using the data prop
    // This code will only run if the data prop changes
    return performExpensiveCalculations(data);
  }, [data]);

  return (
    <div>
      <h2>Expensive Component</h2>
      <p>Result: {expensiveResult}</p>
    </div>
  );
};

const App = () => {
  const data = 'some data';

  return (
    <div>
      <h1>React App</h1>
      <ExpensiveComponent data={data} />
    </div>
  );
};

export default App;