Skip to content

ref(utils): Add functional updater support to useSessionStorage#111015

Open
jaydgoss wants to merge 3 commits intomasterfrom
jaygoss/ref-session-storage-functional-updater
Open

ref(utils): Add functional updater support to useSessionStorage#111015
jaydgoss wants to merge 3 commits intomasterfrom
jaygoss/ref-session-storage-functional-updater

Conversation

@jaydgoss
Copy link
Member

Summary

  • Support SetStateAction<T> (function updater) in useSessionStorage's setter, matching React's useState API
  • Prevents stale-state bugs when multiple sequential calls spread the same snapshot, since each updater receives the latest prev value
  • Adds spec file with 6 tests covering direct values, functional updaters, sequential calls, and item removal

Split out from #110883 per review feedback.

Test plan

  • CI=true pnpm test static/app/utils/useSessionStorage.spec.tsx -- 6 tests passing
  • Key test: sequential functional updaters don't clobber each other ({a: 1} then {b: 2} results in {a: 1, b: 2})

Support SetStateAction<T> (function updater) in useSessionStorage's
setter, matching React's useState API. This prevents stale-state bugs
when multiple sequential calls spread the same snapshot, since each
updater receives the latest prev value.
@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Mar 18, 2026
@jaydgoss jaydgoss marked this pull request as ready for review March 18, 2026 20:00
@jaydgoss jaydgoss requested a review from a team March 18, 2026 20:41
setState(prev => {
const next =
typeof valueOrUpdater === 'function'
? (valueOrUpdater as (prev: T) => T)(prev)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to cast this?

Copy link
Member Author

@jaydgoss jaydgoss Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cast is needed because TypeScript can't narrow SetStateAction<T> (T | ((prev: T) => T)) via typeof === 'function' when T could theoretically be a function type. Constraining T to exclude functions would fix the narrowing but results in a verbose generic signature for a general-purpose utility. Added a comment explaining the cast instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is kicking off a free cloud agent to fix this issue. This run is complimentary, but you can enable autofix for all future PRs in the Cursor dashboard.

Ensures removeItem goes through React's setState queue, so it can't
race with a pending wrappedSetState updater that would write the
value back to storage after removal.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants