Back to all notes

First Render Detection: Skip useEffect for One‑Time Render Logic

Use a ref to run logic only on the first render without effects.

2 min read

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

  1. Create const isFirstRender = useRef(true).

  2. During render, check if (isFirstRender.current).

  3. Run your one-time logic, then set isFirstRender.current = false.

  4. 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 useEffect with 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; }