Repository navigation
fix: memoize compiled component in Preview to preserve state across re-renders - #92
Merged
Merged
Conversation
Copilot
AI
changed the title
[WIP] Fix preview recompilation on every render
fix: memoize compiled component in Preview to preserve state across re-renders
Jun 29, 2026
JeremyRH
approved these changes
Jun 29, 2026
JeremyRH
force-pushed
the
copilot/fix-preview-recompile-issue
branch
from
June 30, 2026 01:28
7e7edb5 to
5d8983b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PreviewcalledevalModule(code, availableImports)directly in the render body.evalModuleruns Babeltransform+new Function(...)on every call, soDefaultExportwas a fresh function reference on every render. React keys component instances by type identity, causing an unmount/remount — and full state reset — on any re-render that didn't originate from a code edit (e.g. args/controls change, globals update via a decorator).Changes
src/Preview.tsx— wrapevalModuleinReact.useMemo([code]).availableImportsis intentionally excluded from deps: callers spread a fresh object on every render ({ react: React, ...state.availableImports }), so including it would bust the memo every render. Error handling is moved inside the memo, returning an error-rendering component function so it's compatible with the memoization path.Side effect: Babel
transformno longer runs on every render, only on actual code changes.src/index.test.tsx— two new tests:componentPropschange butcodeis unchangedcodechanges (correct remount behavior validated)