React Hooks Explained: When to Use useState vs useEffect

React Hooks Explained: When to Use useState vs useEffect

React has transformed web development with its intuitive hooks, enabling developers to manage state and side effects seamlessly. Among these hooks, useState and useEffect are the most widely used, yet knowing when to use each can be tricky. This guide simplifies their purposes and usage with practical examples—perfect for QuickBlox users and React developers.


What is useState in React?

useState is your go-to hook for managing dynamic data in a React component. Think of it as a container for values that directly affect your app's user interface.

When to Use useState

Use useState when:

  • Your app needs to store and update data locally.

  • UI updates are triggered based on changing values like inputs, toggles, or counters.

QuickBlox Examples of useState

  1. Managing Active Chat Users
const [activeUsers, setActiveUsers] = useState([]);

return (
  <div>
    {activeUsers.map(user => (
      <p key={user.id}>{user.name}</p>
    ))}
    <button onClick={() => setActiveUsers([...activeUsers, { id: 5, name: "New User" }])}>
      Add User
    </button>
  </div>
);

📌 Result: Dynamically displays active chat users and updates the UI when a new user is added.

  1. Tracking the Active Chat Tab
const [activeChat, setActiveChat] = useState("General");

return (
  <div>
    <button onClick={() => setActiveChat("General")}>General</button>
    <button onClick={() => setActiveChat("Support")}>Support</button>
    <p>Current Chat: {activeChat}</p>
  </div>
);

📌 Result: Updates the displayed active chat tab when the user switches tabs.


What is useEffect in React?

useEffect is designed to handle side effects—anything that interacts with the outside world or occurs beyond the React rendering process. This includes:

  • Fetching API data.

  • Subscribing to events.

  • Cleaning up timers or resources.

When to Use useEffect

Use useEffect when:

  • React components need to perform actions after rendering.

  • Side effects depend on specific state changes.

  • Cleanup is necessary, such as removing event listeners or canceling subscriptions.

QuickBlox Examples of useEffect

  1. Fetching Chat Messages
useEffect(() => {
  QuickBlox.chat.getMessages({ chatId: activeChat })
    .then(messages => console.log(messages))
    .catch(error => console.error(error));
}, [activeChat]);

📌 Result: Fetches and logs chat messages whenever the active chat changes.

  1. Setting Up Presence Notifications
useEffect(() => {
  const handlePresence = user => console.log(`${user.name} is online`);
  QuickBlox.chat.on("presence", handlePresence);

  return () => QuickBlox.chat.off("presence", handlePresence); // Cleanup
}, []);

📌 Result: Displays online notifications for users and removes listeners on component unmount.


Key Differences Between useState and useEffect

Here’s a quick comparison to guide your decision:

AspectuseStateuseEffect
PurposeManage dynamic data that affects the UI.Handle side effects triggered by state changes or component lifecycle.
TriggersUpdates the UI when the state changes.Executes code based on dependencies.
Examples- Track active users or form inputs.- Fetch chat messages or set up listeners.

Combining useState and useEffect

Many React components leverage both useState and useEffect to deliver dynamic, real-time functionality.

Example: Fetching Messages Based on User Actions

const [activeChat, setActiveChat] = useState("General");
const [messages, setMessages] = useState([]);

useEffect(() => {
  QuickBlox.chat.getMessages({ chatId: activeChat })
    .then(setMessages)
    .catch(console.error);
}, [activeChat]);

return (
  <div>
    <button onClick={() => setActiveChat("General")}>General</button>
    <button onClick={() => setActiveChat("Support")}>Support</button>
    <ul>
      {messages.map(msg => <li key={msg.id}>{msg.content}</li>)}
    </ul>
  </div>
);

📌 Result: Updates and displays chat messages dynamically when the active chat changes.


Common Mistakes and Best Practices

1. Avoid Infinite Loops in useEffect

Incorrect usage can lead to endless re-renders:

useEffect(() => {
  setCount(count + 1); // ❌ Avoid this
});

✅ Fix: Ensure dependencies are correctly managed.

2. Always Clean Up Resources

Prevent memory leaks by cleaning up timers, listeners, or subscriptions:

useEffect(() => {
  const handleResize = () => console.log("Resized");
  window.addEventListener("resize", handleResize);

  return () => window.removeEventListener("resize", handleResize); // Cleanup
}, []);

Conclusion

  • Use useState to manage dynamic data that drives your UI.

  • Use useEffect for handling side effects that interact with external systems or lifecycles.

  • Combine both hooks for powerful, responsive components.

Mastering these hooks will help you build efficient, scalable React applications. Start experimenting today to fully unlock the potential of hooks like useState and useEffect!
You can also start experimenting by building apps with QuickBlox. Sign up here to get started!