First Render Detection: Skip useEffect for One‑Time Render Logic
Use a ref to run logic only on the first render without effects.
Introduction
First render detection is a pattern where you detect and handle the very first render without using useEffect. It relies on refs so you can run one‑time logic during render without extra effects.
Why this matters
Sometimes you need logic to run exactly once on the first render, and an empty‑deps useEffect feels heavy or mistimed. A ref checked during render is simpler.
The problem
Detecting first render with useEffect(() => {}, []) runs after paint and can be ill‑timed for logic that must happen during render. Using state to track first render also causes an extra render.
Inefficient approach
Effect or state adds overhead and timing mismatches:
import { useState, useEffect } from "react";
function App() {
const [isFirst, setIsFirst] = useState(true);
useEffect(() => {
if (isFirst) {
console.log("First render");
setIsFirst(false);
}
}, [isFirst]);
return (
<div>
<h1>First Render Detection</h1>
<p>Check console for first render log</p>
</div>
);
}
export default App;
The solution
Use useRef(true), check it during render, then flip it to false.
import { useRef } from "react";
function App() {
const isFirstRender = useRef(true);
if (isFirstRender.current) {
console.log("First render");
isFirstRender.current = false;
}
return (
<div>
<h1>First Render Detection</h1>
<p>Check console for first render log</p>
</div>
);
}
export default App;
Step-by-step
-
Create
const isFirstRender = useRef(true). -
During render, check
if (isFirstRender.current). -
Run your one-time logic, then set
isFirstRender.current = false. -
Avoid side effects here; prefer idempotent or render‑safe logic.
Tips
-
Keep first‑render logic side‑effect free or idempotent—this runs during render.
-
For effects that truly must run after paint, prefer
useEffectwith empty deps. -
Avoid storing render‑time flags in state; refs won’t trigger re‑renders.
Knowledge base
Problem snippet:
useEffect(() => { console.log("First render"); }, []);
Solution snippet:
const isFirstRender = useRef(true);
if (isFirstRender.current) { console.log("First render"); isFirstRender.current = false; }