What's new
NoobsPlanet

Join our community today and enjoy an ad-free experience. Ask questions or learn about anything related to technology!

⚛️ Using useEffect in React to Handle Side Effects

Nikesh

Administrator
Staff member
In this guide, we’ll learn how to use the `useEffect` hook in React to manage side effects such as triggering actions after a state change.

This is a powerful pattern, especially when you want to respond to a state like `loading` and do something like:
- Fetch data
- Start a timeout
- Perform animations
- Or any side-effect that should happen after a certain condition.

Let’s build it step-by-step!

1️⃣ Props and Union Types Setup

First, we define the props for our button and a union type to manage different states.

JavaScript:
interface MyButtonProps {
  title: string;
  disabled: boolean;
}

type RequestState<T = unknown> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error };
This gives us the structure for a component that can react to different request states in a type-safe way.

2️⃣ The MyButton Component with useEffect

Now we build the component logic. This time, instead of triggering the state change inside the click handler, we just set it to `'loading'`.
The actual work (side-effect) happens inside `useEffect`.

JavaScript:
import { useEffect, useState } from "react";

function MyButton({ title, disabled }: MyButtonProps) {
  const [requestState, setRequestState] = useState<RequestState<string>>({ status: 'idle' });
  const [enabled, setEnabled] = useState<boolean>(true);

  const handleClick = () => {
    setRequestState({ status: 'loading' }); // Trigger side-effect
  };

  useEffect(() => {
    if (requestState.status === 'loading') {
      const timeout = setTimeout(() => {
        setRequestState({ status: 'success', data: 'Success!' });
        setEnabled((prev) => !prev);
      }, 1000);

      // Cleanup function
      return () => clearTimeout(timeout);
    }
  }, [requestState.status]);

  return (
    <>
      <button disabled={disabled || !enabled} onClick={handleClick}>
        {title}
      </button>
      <p>Status: {requestState.status}</p>
      {requestState.status === 'success' && <p>Result: {requestState.data}</p>}
    </>
  );
}
What's happening here?
- On button click → state becomes `'loading'`.
- `useEffect` sees that status changed to `'loading'`, and starts a `setTimeout`.
- After 1 second, the request becomes `'success'`, and button toggle logic runs.
- There’s a cleanup function to clear timeout if the component unmounts.

3️⃣ MyApp Component to Render the Button

Finally, we wrap the `MyButton` inside a simple app:

JavaScript:
export default function MyApp() {
  return (
    <div>
      <h1>My App</h1>
      <MyButton title="I am a button" disabled={false} />
    </div>
  );
}
🔍 Why useEffect is Better Here?

This pattern separates the event trigger (click) from the side effect logic (timeout and state change).

That makes the code more declarative, easier to test, and scalable for things like:
- Fetching data from APIs
- Reacting to prop changes
- Animations or DOM manipulations

✅ Summary

- We used useEffect to handle what happens after a click event.
- Combined with useState and union types, this is a powerful structure for real-world apps.
- Always remember to cleanup side effects (like timeouts) inside `useEffect`.

Let me know if you'd like to see this example expanded with API calls or error handling next! 🚀
 
Top