Try @eslint-react/kit@beta
logoESLint React

purity

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

This is an evaluation implementation and may contain false positives or negatives that have not yet been fully audited. Review each report carefully before applying fixes.

Full Name in eslint-plugin-react-x

react-x/purity

Full Name in @eslint-react/eslint-plugin

@eslint-react/purity

Presets

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

Rule Details

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.

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()

Examples

Generating random values during render

Random values change on every render, making the component's output unpredictable. This breaks memoization and can cause hydration mismatches in server-rendered apps.

// Problem: produces a different value on every render
function Component() {
  const id = Math.random(); // different on every render
  //         ^^^ 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>;
}
// Problem: calling crypto.randomUUID() directly during render
function Component() {
  const id = crypto.randomUUID(); // different on every render
  //         ^^^ Do not call 'crypto.randomUUID()' during render. Components and hooks must be pure. Move this call into an event handler, effect, or state initializer.
  return <div id={id}>Content</div>;
}
// Recommended: use lazy initialization to ensure a stable value
function Component() {
  const [id] = useState(() => crypto.randomUUID());
  return <div key={id}>Content</div>;
}
// Problem: useMemo cannot make an impure call pure
function Component() {
  const value = useMemo(() => 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>{value}</div>;
}

Using time-based values during render

Time-based values change constantly. Using them directly in render makes the component impure and causes unnecessary re-renders or hydration issues.

// Problem: time-based value changes on every render
function Component() {
  const timestamp = Date.now(); // constantly changing
  //                ^^^ 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>;
}
// Problem: new Date() is also impure
function Component() {
  const date = new Date(); // new time on every render
  //           ^^^ 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>;
}
// Recommended: use time-based values in effects or event handlers
function Component() {
  useEffect(() => {
    const timestamp = Date.now();
    console.log(timestamp);
  }, []);
  return <div>Content</div>;
}

Using time-based values in custom hooks

Custom hooks are also part of the render phase, so impure calls inside them are flagged just like in components.

// Problem: impure call inside a custom hook
function useTimestamp() {
  const t = Date.now(); // called during render
  //        ^^^ 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;
}
// Recommended: move impure logic into an effect
function useTimestamp() {
  const [timestamp, setTimestamp] = useState(() => Date.now());
  useEffect(() => {
    setTimestamp(Date.now());
  }, []);
  return timestamp;
}

Impure calls in event handlers and effects

Event handlers and effects run outside of React's render cycle, so impure functions are perfectly acceptable there.

// Recommended: use random numbers in event handlers
function Component() {
  return (
    <button onClick={() => console.log(Math.random())}>
      Roll
    </button>
  );
}
// Recommended: use timestamps in effects
function Component() {
  useEffect(() => {
    const timestamp = Date.now();
    console.log(timestamp);
  }, []);
  return <div>Content</div>;
}

Showing the current time

Calling Date.now() directly in JSX produces a different value on every render and makes the component impure.

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

When you need to display a constantly updating value like the current time, use state and an effect rather than calling Date.now() directly in render.

// Recommended: manage time with state and effects
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>;
}

Versions

Resources

Further Reading


See Also

On this page