logoESLint React
Rules

purity

Full Name in @eslint-react/eslint-plugin@beta

@eslint-react/purity

Full Name in eslint-plugin-react-x@beta

react-x/purity

Presets

x recommended recommended-typescript recommended-type-checked strict strict-typescript strict-type-checked

Description

Validates that components and hooks are pure by checking that they do not call known-impure functions during render.

React components must be pure functions — given the same props, they should always return the same JSX. When components use functions like Math.random() or Date.now() during render, they produce different output each time, breaking React's assumptions and causing bugs like hydration mismatches, incorrect memoization, and unpredictable behavior.

Common Violations

In general, any API that returns a different value for the same inputs violates this rule. Usual examples include:

  • Math.random()
  • Date.now() / new Date()
  • crypto.randomUUID() / crypto.getRandomValues()
  • performance.now()

Invalid

// ❌ Math.random() in render
function Component() {
  const id = Math.random(); // Different every render
  return <div key={id}>Content</div>;
}
// ❌ Date.now() for values
function Component() {
  const timestamp = Date.now(); // Changes every render
  return <div>Created at: {timestamp}</div>;
}
// ❌ new Date() in render
function Component() {
  const date = new Date(); // Different every render
  return <div>{date.toISOString()}</div>;
}

Valid

// ✅ Stable IDs from initial state
function Component() {
  const [id] = useState(() => crypto.randomUUID());
  return <div key={id}>Content</div>;
}
// ✅ Impure calls in event handlers
function Component() {
  return (
    <button onClick={() => console.log(Math.random())}>
      Roll
    </button>
  );
}
// ✅ Impure calls inside effects
function Component() {
  useEffect(() => {
    const timestamp = Date.now();
    console.log(timestamp);
  }, []);
  return <div>Content</div>;
}

Troubleshooting

I need to show the current time

Calling Date.now() during render makes your component impure:

// ❌ Wrong: Time changes every render
function Clock() {
  return <div>Current time: {Date.now()}</div>;
}

Instead, move the impure function outside of render:

// ✅ Correct: Initialize in state, update in effect
function Clock() {
  const [time, setTime] = useState(() => Date.now());
  useEffect(() => {
    const interval = setInterval(() => {
      setTime(Date.now());
    }, 1000);
    return () => clearInterval(interval);
  }, []);
  return <div>Current time: {time}</div>;
}

I need a unique ID

Calling crypto.randomUUID() or Math.random() during render produces a different value on every render:

// ❌ Wrong: ID changes every render
function Component() {
  const id = crypto.randomUUID();
  return <div id={id}>Content</div>;
}

Instead, wrap the call in a state initializer so it only runs once:

// ✅ Correct: ID is stable across renders
function Component() {
  const [id] = useState(() => crypto.randomUUID());
  return <div id={id}>Content</div>;
}

Examples

Failing

function Component() {
  const id = Math.random();
  //         ^^^^^^^^^^^^^
  //         - Do not call 'Math.random()' during render. Components and hooks must be pure.
  //           Move this call into an event handler, effect, or state initializer.
  return <div key={id}>Content</div>;
}
function Component() {
  const timestamp = Date.now();
  //                ^^^^^^^^^^
  //                - Do not call 'Date.now()' during render. Components and hooks must be pure.
  //                  Move this call into an event handler, effect, or state initializer.
  return <div>Created at: {timestamp}</div>;
}
function Component() {
  const date = new Date();
  //           ^^^^^^^^^^
  //           - Do not call 'new Date()' during render. Components and hooks must be pure.
  //             Move this call into an event handler, effect, or state initializer.
  return <div>{date.toISOString()}</div>;
}
function useTimestamp() {
  const t = Date.now();
  //        ^^^^^^^^^^
  //        - Do not call 'Date.now()' during render. Components and hooks must be pure.
  //          Move this call into an event handler, effect, or state initializer.
  return t;
}

Passing

function Component() {
  const [id] = useState(() => crypto.randomUUID());
  return <div key={id}>Content</div>;
}
function Component() {
  return (
    <button onClick={() => console.log(Math.random())}>
      Roll
    </button>
  );
}
function Component() {
  useEffect(() => {
    const timestamp = Date.now();
    console.log(timestamp);
  }, []);
  return <div>Content</div>;
}
function Component() {
  const value = useMemo(() => Math.random(), []);
  return <div>{value}</div>;
}

Implementation

Further Reading

On this page