ReactJS Hooks revolutionized how developers manage state and lifecycle methods in React. Introduced in React 16.8, they allow you to use state and other React features in functional components, making them a powerful alternative to class components.
What Are React Hooks?
Hooks are special functions in React that let you "hook into" React's core features like state, lifecycle methods, and context. With hooks, you can:
- Manage state: Use useStateto handle component-specific data.
- Handle side effects: Use useEffectfor tasks like fetching data or DOM updates.
- Use context: Share data globally across components with useContext.
- Optimize performance: Use hooks like useMemoanduseCallback.
Let’s dive into the most commonly used hooks with detailed explanations and examples.
1. useState: Managing State in Functional Components
The useState hook allows you to add state to functional components. Imagine you’re creating a simple counter app where users can increase or decrease a number.
Example:
import React, { useState } from 'react';
 
function Counter() {
  const [count, setCount] = useState(0); // Initialize state with 0
 
  return (
    <div>
      <p>Current Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
      <button onClick={() => setCount(count - 1)}>Decrease</button>
    </div>
  );
}
 
export default Counter;How It Works:
- useState(0)initializes the- countvariable with a value of- 0.
- setCountis the function to update- count.
- Clicking the buttons updates the state, triggering a re-render of the component.
Real-World Use Case: A voting system where users can upvote or downvote an item.
2. useEffect: Handling Side Effects
The useEffect hook is used for side effects like fetching data, setting up subscriptions, or manually updating the DOM. Think of it as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount in class components.
Example:
import React, { useState, useEffect } from 'react';
 
function UserList() {
  const [users, setUsers] = useState([]);
 
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then(response => response.json())
      .then(data => setUsers(data));
  }, []); // Empty array ensures this runs only once
 
  return (
    <div>
      <h1>User List</h1>
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}
 
export default UserList;How It Works:
- The useEffecthook runs after the component renders.
- The empty dependency array []ensures the effect runs only once, similar tocomponentDidMount.
- Data fetched from the API is stored in the usersstate, which updates the component.
Real-World Use Case: Automatically fetching a product list when a user visits an e-commerce site.
3. useContext: Simplifying Global State
The useContext hook simplifies accessing global state, removing the need to pass props through every level of a component tree.
Example:
import React, { createContext, useContext } from 'react';
 
const ThemeContext = createContext('light');
 
function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{
      backgroundColor: theme === 'dark' ? '#333' : '#fff',
      color: theme === 'dark' ? '#fff' : '#000'
    }}>
      I am a {theme} button
    </button>
  );
}
 
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}
 
export default App;How It Works:
- ThemeContextprovides a global theme value (- lightor- dark).
- useContextretrieves the current value of the context (- darkin this case).
- The button’s style changes based on the theme.
Real-World Use Case: Switching between light and dark themes in an application.
4. Advanced Hooks
useReducer
For managing complex state logic, useReducer works like Redux but simpler. It’s useful for apps like shopping carts.
Example:
import React, { useReducer } from 'react';
 
const initialState = { count: 0 };
 
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}
 
function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
 
  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increase</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrease</button>
    </div>
  );
}
 
export default Counter;How It Works:
- useReducermanages state transitions based on- actiontypes.
- dispatchsends actions to the reducer function.
Real-World Use Case: Managing a to-do list with actions like "add", "delete", and "toggle".
Other Hooks:
- useMemo: Avoids recalculating expensive functions unless dependencies change.
- useCallback: Memoizes callback functions to prevent unnecessary renders.
- useRef: Accesses DOM elements or stores mutable values without triggering re-renders.
Why React Hooks?
Hooks simplify React development by:
- Eliminating the need for class components: Write less boilerplate.
- Making code reusable: Custom hooks allow for cleaner, reusable logic.
- Improving readability: Functional components are easier to understand and maintain.
- Providing flexibility: Use multiple hooks in the same component.
Conclusion
React Hooks are a game-changer for modern React development. They make managing state, handling side effects, and optimizing performance easier. Start with useState and useEffect, then gradually explore advanced hooks like useReducer and useContext.