Skip to main content

useDidUpdate

A Hook that executes a callback when the component updates, skipping the initial mount, equivalent to the componentDidUpdate lifecycle method in class components.

Basic Usage

Live Editor
function Demo() {
  const [count, setCount] = useState(0);
  const [updateCount, setUpdateCount] = useState(0);

  useDidUpdate(() => {
    setUpdateCount((c) => c + 1);
  }, [count]);

  return (
    <div>
      <div
        style={{
          padding: '20px',
          backgroundColor: 'var(--ifm-color-emphasis-100)',
          borderRadius: '8px',
          marginBottom: '12px',
        }}
      >
        <div>Count: {count}</div>
        <div style={{ color: 'var(--ifm-color-primary)' }}>
          Update count: {updateCount}
        </div>
      </div>
      <Button onClick={() => setCount(count + 1)}>Increment</Button>
    </div>
  );
}
Result
Loading...

Monitor Specific Values

Execute only when specific dependencies change:

Live Editor
function Demo() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [log, setLog] = useState([]);

  useDidUpdate(() => {
    setLog((logs) => [...logs, `Name updated to: ${name}`]);
  }, [name]);

  return (
    <div>
      <div style={{ marginBottom: '12px' }}>
        <Input
          placeholder="Enter name"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
      </div>
      <div style={{ marginBottom: '12px' }}>
        <Input
          placeholder="Enter email (won't trigger log)"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
      </div>
      {log.length > 0 && (
        <div
          style={{
            padding: '12px',
            backgroundColor: 'var(--ifm-color-emphasis-100)',
            borderRadius: '6px',
            fontSize: '14px',
          }}
        >
          <strong>Update log:</strong>
          {log.map((item, index) => (
            <div key={index}>{item}</div>
          ))}
        </div>
      )}
    </div>
  );
}
Result
Loading...

Sync to localStorage

Sync to local storage when value changes:

Live Editor
function Demo() {
  const [text, setText] = useState('');
  const [saved, setSaved] = useState(false);

  useDidUpdate(() => {
    localStorage.setItem('draft-text', text);
    setSaved(true);
    const timer = setTimeout(() => setSaved(false), 2000);
    return () => clearTimeout(timer);
  }, [text]);

  return (
    <div>
      <Textarea
        placeholder="Enter text (auto-save)"
        value={text}
        onChange={(e) => setText(e.target.value)}
        rows={4}
      />
      {saved && (
        <div
          style={{
            marginTop: '12px',
            padding: '8px 12px',
            backgroundColor: 'var(--ifm-color-success-lightest)',
            borderRadius: '4px',
            fontSize: '14px',
          }}
        >
          ✓ Saved
        </div>
      )}
    </div>
  );
}
Result
Loading...

Form Validation

Execute validation when fields change:

Live Editor
function Demo() {
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState('');

  useDidUpdate(() => {
    if (password && confirmPassword) {
      if (password !== confirmPassword) {
        setError('Passwords do not match');
      } else {
        setError('');
      }
    }
  }, [password, confirmPassword]);

  return (
    <div>
      <div style={{ marginBottom: '12px' }}>
        <Input
          type="password"
          placeholder="Enter password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
      </div>
      <div style={{ marginBottom: '12px' }}>
        <Input
          type="password"
          placeholder="Confirm password"
          value={confirmPassword}
          onChange={(e) => setConfirmPassword(e.target.value)}
        />
      </div>
      {error && (
        <div
          style={{
            padding: '8px 12px',
            backgroundColor: 'var(--ifm-color-danger-lightest)',
            color: 'var(--ifm-color-danger-dark)',
            borderRadius: '4px',
            fontSize: '14px',
          }}
        >
          {error}
        </div>
      )}
    </div>
  );
}
Result
Loading...

API

Parameters

function useDidUpdate(
fn: () => void,
dependencies?: any[]
): void
ParameterDescriptionTypeDefault
fnCallback function executed on update() => void-
dependenciesDependency arrayany[]undefined

Return Value

No return value.

Difference from useEffect

FeatureuseDidUpdateuseEffect
Initial mount❌ Does not execute✅ Executes
On update✅ Executes✅ Executes
Use caseOnly care about updatesCare about mount and updates

Notes

  • Callback is not executed on initial component mount
  • Only executes when dependencies change
  • If no dependency array is passed, executes on every update
  • Avoid modifying dependency values inside the callback, which may cause infinite loops

Usage Scenarios

  • Data Synchronization: Sync to external systems when state changes
  • Form Validation: Execute validation when fields change
  • Logging: Record value changes
  • Side Effects: Respond to specific state changes
  • API Calls: Re-fetch data when search term changes