TL;DR: There are two copies of React in your module tree, and the component is calling hooks on the copy that has no dispatcher set. Run npm ls react to find the duplicate, then align react and react-dom to one version and dedupe. Linked local packages should list react as a peer dependency, never a bundled dependency.

## The error

```text
"TypeError: Cannot read properties of undefined (reading 'useState')" after a react version mismatch
```

## Steps to fix

1. Find the duplicates: npm ls react and npm ls react-dom (or the yarn/pnpm equivalent).
   Expected: The tree shows react installed at two different versions or nested under a linked package's node_modules.

2. Align the versions: set react and react-dom to the same version in package.json and run npm dedupe (or yarn dedupe).
   Expected: A second npm ls react shows exactly one version at the top level.

3. If a linked local package carries its own react, move react and react-dom to its peerDependencies and reinstall.
   Expected: The linked package resolves react from the app's node_modules instead of its own copy.

4. Clear and reinstall: remove node_modules and the lockfile entry noise with a fresh npm install, then rebuild.
   Expected: The app boots and hooks work with no useState error.

## Use this when

- React crashes with Cannot read properties of undefined (reading 'useState') after a version mismatch or upgrade
- Hooks break only when a locally linked package is used
- Two major React versions appear in the dependency tree

## Not for this skill when

- Hooks called conditionally or outside components, which throw the invalid hook call warning for a different reason
- react-dom/server rendering mismatches, which are hydration problems
- Build-time JSX transform errors, which fail before any hook runs

## Variant phrasings

- Cannot read properties of undefined reading useEffect after react upgrade
- Invalid hook call warning with two react copies
- react 18 and react 19 both installed

## Why it happens

Hooks work through a per-copy dispatcher: the react package your component imports must be the same copy that react-dom initializes. When the bundler resolves two copies (common with npm link, monorepos, or a react 18 library inside a react 19 app), the component calls useState on a copy whose dispatcher was never set, so the read happens on undefined. Matching versions plus a single resolved copy restores the one-dispatcher invariant.

## Edge cases

- pnpm's strict node_modules layout makes duplicates more visible but the same rule applies: one react per app.
- Some component libraries legitimately support a range of react versions; keep the range in peerDependencies and test the extremes in CI.
- After dedupe, verify with the bundler's stats that only one react module is included; lockfiles can reintroduce the duplicate on the next install.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_-MCvrbXoGMIf0S4S6xF7SA
