Skip to content

Latest commit

 

History

History
127 lines (89 loc) · 3 KB

File metadata and controls

127 lines (89 loc) · 3 KB
title purity
version rc

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

This rule is available in eslint-plugin-react-hooks v6.

Rule Details {/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.

Common Violations {/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()
  • performance.now()

Invalid {/invalid/}

Examples of incorrect code for this rule:

// ❌ 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>;
}

Valid {/valid/}

Examples of correct code for this rule:

// ✅ Stable IDs from initial state
function Component() {
  const [id] = useState(() => crypto.randomUUID());
  return <div key={id}>Content</div>;
}

Troubleshooting {/troubleshooting/}

I need to show random content {/random-content/}

Calling Math.random() during render makes your component impure:

const messages = ['a', 'b', 'c'];

// ❌ Wrong: Random message changes every render
function RandomMessage() {
  return (
    <div>
      Random message: {messages[Math.floor(messages.length * Math.random())]}
    </div>
  );
}

Instead, move the impure function into an effect:

const messages = ['a', 'b', 'c'];

function RandomMessage() {
  const [message, setMessage] = useState('');

  useEffect(() => {
    setMessage(messages[Math.floor(messages.length * Math.random())]);
  }, []);

  if (message === '') return;

  return <div>Random message: {message}</div>;
}

I need to show the current time {/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:

function Clock() {
  const [time, setTime] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setTime(Date.now());
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  if (time === 0) return;

  return <div>Current time: {time}</div>;
}