React useEffect
useEffect is used when your React component needs to synchronize with something outside React.
Examples of external systems:
- Timers
- WebSocket connections
- Browser event listeners
- API subscriptions
- Third-party libraries
A simple rule:
If there is no external system to synchronize with, you probably do not need
useEffect.
Basic syntax
useEffect(() => {
// Synchronize with something outside React return () => {
// Clean up if needed
};
}, [dependencies]);An Effect runs after React renders the component.
useEffect(() => {
console.log("Room changed");
}, [roomId]);This runs:
- When the component first appears
- Whenever
roomIdchanges
Dependency array patterns
useEffect(() => {
// Runs after every render
});useEffect(() => {
// Runs after the component first appears
}, []);useEffect(() => {
// Runs after first render and whenever userId changes
}, [userId]);Effects are not for user actions
Use event handlers for things caused by the user, such as clicks, typing, and form submissions.
function Counter() {
const [count, setCount] = useState(0);function handleClick() {
setCount(count + 1);
} return <button onClick={handleClick}>{count}</button>;
}
There is no need for an Effect here.
Get Rahulspagidimarri’s stories in your inbox
Join Medium for free to get updates from this writer.
A good distinction is:
- Component appears or updates →
useEffect - User clicks, types, or submits → event handler
Avoid direct DOM manipulation when React can handle it
React gives us built-in event props such as onChange.
import { useState } from "react";export default function App() {
const [input, setInput] = useState(""); function handleInput(event) {
setInput(event.target.value);
} return (
<>
<input value={input} onChange={handleInput} />
<p>{input}</p>
</>
);
}
Usually, avoid manually using:
document.getElementById(...)React event handlers are cleaner and automatically managed.
Clean up what you start
If an Effect starts a timer, listener, or connection, clean it up.
useEffect(() => {
const intervalId = setInterval(() => {
console.log("Running...");
}, 1000); return () => {
clearInterval(intervalId);
};
}, []);Cleanup runs when:
- The component is removed from the UI
- Dependencies change before the Effect runs again
The three questions to ask
Before writing an Effect, ask:
Example:
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect(); return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);Final rule
Render for UI.
Event handlers for user actions.
Effects for external synchronization.
Avoid using Effects to calculate values, reset state, or make components communicate. In many cases, derived values, React keys, or lifting state to a parent are cleaner solutions.




