Skip to content

fix: apply batched functional updates in useControllableState - #80

Merged
TheGreatAxios merged 1 commit into
cl-9399-react-ui-align-repo-scaffolding-with-the-package-standardfrom
cl-9431-react-ui-functional-updates
Sep 27, 2026
Merged

TheGreatAxios merged 1 commit into
cl-9399-react-ui-align-repo-scaffolding-with-the-package-standardfrom
cl-9431-react-ui-functional-updates

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Closes CL-9431

In uncontrolled mode the setter resolved functional updates against the value captured at render, so two batched setValue((p) => p + 1) calls both saw the same base and produced 1 instead of 2 (and useDismissablePopover's double toggle stayed open).

The setter now resolves against a ref that holds the latest uncontrolled value and is updated synchronously on every set, then passes the result to setUncontrolledValue and onChange. Controlled mode still resolves against the controlled value.

Why a ref, not a React updater: calling onChange inside an updater would fire it twice under StrictMode, which double-invokes updaters. Keeping the side effect in the setter fires onChange once per call.

Tests: two batched functional updates give 2 with onChange called with 1 then 2 (via renderHook); onChange fires once under StrictMode; two batched useDismissablePopover toggles end closed. No public API change.

@TheGreatAxios
TheGreatAxios added this pull request to stack #74 September 27, 2026 00:33
@TheGreatAxios
TheGreatAxios merged commit 926c8ec into main Sep 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant