useDefaultLoading saved progress…

useDefault

Build a custom React hook that works exactly like useState, with one twist: whenever the stored state is null or undefined, reading the value gives you a fallback default instead. It's the hook you reach for when a value might legitimately go missing — a form field that hasn't loaded, an API response that came back empty — and you'd rather render a sensible placeholder than undefined. The catch is that "missing" must mean only null or undefined, never a real value that happens to be falsy.

Signature

function useDefault<T>(
  defaultValue: T,
  initialValue: T | null | undefined
): [T, (next: T | null | undefined) => void];

useDefault returns a [value, setValue] pair. setValue behaves like a normal state setter. When the stored state is null or undefined, value reads as defaultValue.

Examples

function Greeting({ name }) {
  const [displayName, setDisplayName] = useDefault('Guest', name);
  return <h1>Hello, {displayName}</h1>;
}
// name = 'Ada'      → "Hello, Ada"
// name = undefined  → "Hello, Guest"
// name = null       → "Hello, Guest"
// Falsy-but-real values must survive — they are NOT replaced:
useDefault('fallback', 0);      // value === 0
useDefault('fallback', '');     // value === ''
useDefault('fallback', false);  // value === false

// Setting the state to null or undefined brings the default back:
const [value, setValue] = useDefault('fallback', 'hi');
setValue(null);                 // value === 'fallback'

Notes

  • Only null and undefined trigger the fallback. 0, '', and false are real values and must pass through unchanged. This is the whole point of the hook.
  • setValue is a plain state setter. It accepts a value and updates the state, just like the setter from useState. Supporting a functional updater is a nice-to-have, not a requirement.
  • The default applies on read, not on write. You don't overwrite the stored state with the default — the state can still hold null. You only substitute the default when handing the value back.
  • The default itself can be any type. A string, number, object, or array — whatever the caller passes.
Loading editor…