Skip to content

fix: make proxy subscribe() synchronous to fix IME composition#56

Merged
Moon-DaeSeung merged 4 commits into
mainfrom
feat/use-model-input
Mar 22, 2026
Merged

fix: make proxy subscribe() synchronous to fix IME composition#56
Moon-DaeSeung merged 4 commits into
mainfrom
feat/use-model-input

Conversation

@Moon-DaeSeung
Copy link
Copy Markdown
Contributor

@Moon-DaeSeung Moon-DaeSeung commented Mar 22, 2026

Summary

  • subscribe()에서 microtask 배칭(Promise.resolve().then()) 제거, 동기 콜백으로 변경
  • zustand과 동일한 접근 — React 18이 자체 배칭하므로 프록시 레벨 배칭은 불필요
  • useModel을 그대로 쓰면 한글/일본어/중국어 IME가 정상 동작

변경 전

onChange → proxy mutation → microtask 대기 → (React가 옛날 값으로 렌더) → IME 깨짐

변경 후

onChange → proxy mutation → subscribe 즉시 호출 → React가 최신 값으로 렌더 → IME 정상

변경 파일

  • proxy.ts: subscribe() — microtask 배칭 제거, 동기 콜백
  • model.ts: 3번째 인자 제거 (불필요)
  • proxy.test.ts: 배칭 테스트 → 동기 호출 테스트로 변경

Test plan

  • 전체 276개 테스트 통과
  • 타입체크 통과
  • API 변경 없음

🤖 Generated with Claude Code

Proxy notifications batched via microtask (Promise.resolve().then())
arrive after React re-renders, causing IME composition (Korean,
Japanese, Chinese) to break in controlled inputs bound to comwit state.

useModelInput() maintains a local state buffer that updates
synchronously on onChange, while pausing proxy→local sync during
IME composition (compositionstart/compositionend). This preserves
the microtask batching optimization for all other subscribers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comwit-docs Ready Ready Preview Mar 22, 2026 2:03pm

Replace the useModelInput() workaround with a proper fix at the proxy
level. The subscribe() function now accepts a notifyInSync flag that
skips microtask batching and fires callbacks synchronously.

StoreEntry.subscribe (the React/useSyncExternalStore path) uses sync
mode so React sees state changes immediately in the same event loop
tick. React 18 already batches state updates, making the microtask
batching redundant for React subscribers. This matches how zustand
(always sync) and valtio (sync opt-in) handle the same problem.

Vanilla subscribers still use the default microtask batching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Moon-DaeSeung Moon-DaeSeung changed the title feat: add useModelInput() hook for IME-safe controlled inputs fix: use sync proxy notifications for React to fix IME composition Mar 22, 2026
No need for a conditional — just make subscribe() always synchronous
like zustand does. React 18 batches renders itself, and persist.ts
already wraps its callback with debounce(). The microtask layer was
redundant for all current subscribers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Moon-DaeSeung Moon-DaeSeung changed the title fix: use sync proxy notifications for React to fix IME composition fix: make proxy subscribe() synchronous to fix IME composition Mar 22, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Moon-DaeSeung Moon-DaeSeung merged commit 7c3b611 into main Mar 22, 2026
1 check passed
@Moon-DaeSeung Moon-DaeSeung deleted the feat/use-model-input branch March 22, 2026 14:05
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