Skip to content

Commit 250f1b2

Browse files
authored
[playground] Fix useEffect on tabify (facebook#34594)
There was a bug in the Compiler Playground related to the "Show Internals" toggle due to a useEffect that was causing the tab names to flicker from a rerender. Rewritten instead with a `<Suspense>` boundary + `use`.
1 parent b0c1dc0 commit 250f1b2

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

compiler/apps/playground/components/Editor/Output.tsx

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,24 @@ import {
1919
import parserBabel from 'prettier/plugins/babel';
2020
import * as prettierPluginEstree from 'prettier/plugins/estree';
2121
import * as prettier from 'prettier/standalone';
22-
import {memo, ReactNode, useEffect, useState} from 'react';
2322
import {type Store} from '../../lib/stores';
23+
import {memo, ReactNode, use, useState, Suspense} from 'react';
2424
import AccordionWindow from '../AccordionWindow';
2525
import TabbedWindow from '../TabbedWindow';
2626
import {monacoOptions} from './monacoOptions';
2727
import {BabelFileResult} from '@babel/core';
28+
import {LRUCache} from 'lru-cache';
2829

2930
const MemoizedOutput = memo(Output);
3031

3132
export default MemoizedOutput;
3233

3334
export const BASIC_OUTPUT_TAB_NAMES = ['Output', 'SourceMap'];
3435

36+
const tabifyCache = new LRUCache<Store, Promise<Map<string, ReactNode>>>({
37+
max: 5,
38+
});
39+
3540
export type PrintedCompilerPipelineValue =
3641
| {
3742
kind: 'hir';
@@ -200,6 +205,25 @@ ${code}
200205
return reorderedTabs;
201206
}
202207

208+
function tabifyCached(
209+
store: Store,
210+
compilerOutput: CompilerOutput,
211+
): Promise<Map<string, ReactNode>> {
212+
const cached = tabifyCache.get(store);
213+
if (cached) return cached;
214+
const result = tabify(store.source, compilerOutput, store.showInternals);
215+
tabifyCache.set(store, result);
216+
return result;
217+
}
218+
219+
function Fallback(): JSX.Element {
220+
return (
221+
<div className="w-full h-monaco_small sm:h-monaco flex items-center justify-center">
222+
Loading...
223+
</div>
224+
);
225+
}
226+
203227
function utf16ToUTF8(s: string): string {
204228
return unescape(encodeURIComponent(s));
205229
}
@@ -213,12 +237,17 @@ function getSourceMapUrl(code: string, map: string): string | null {
213237
}
214238

215239
function Output({store, compilerOutput}: Props): JSX.Element {
240+
return (
241+
<Suspense fallback={<Fallback />}>
242+
<OutputContent store={store} compilerOutput={compilerOutput} />
243+
</Suspense>
244+
);
245+
}
246+
247+
function OutputContent({store, compilerOutput}: Props): JSX.Element {
216248
const [tabsOpen, setTabsOpen] = useState<Set<string>>(
217249
() => new Set(['Output']),
218250
);
219-
const [tabs, setTabs] = useState<Map<string, React.ReactNode>>(
220-
() => new Map(),
221-
);
222251
const [activeTab, setActiveTab] = useState<string>('Output');
223252

224253
/*
@@ -233,13 +262,6 @@ function Output({store, compilerOutput}: Props): JSX.Element {
233262
setTabsOpen(new Set(['Output']));
234263
setActiveTab('Output');
235264
}
236-
237-
useEffect(() => {
238-
tabify(store.source, compilerOutput, store.showInternals).then(tabs => {
239-
setTabs(tabs);
240-
});
241-
}, [store.source, compilerOutput, store.showInternals]);
242-
243265
const changedPasses: Set<string> = new Set(['Output', 'HIR']); // Initial and final passes should always be bold
244266
let lastResult: string = '';
245267
for (const [passName, results] of compilerOutput.results) {
@@ -254,6 +276,7 @@ function Output({store, compilerOutput}: Props): JSX.Element {
254276
lastResult = currResult;
255277
}
256278
}
279+
const tabs = use(tabifyCached(store, compilerOutput));
257280

258281
if (!store.showInternals) {
259282
return (

compiler/apps/playground/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"hermes-eslint": "^0.25.0",
3333
"hermes-parser": "^0.25.0",
3434
"invariant": "^2.2.4",
35+
"lru-cache": "^11.2.2",
3536
"lz-string": "^1.5.0",
3637
"monaco-editor": "^0.52.0",
3738
"next": "15.6.0-canary.7",

compiler/apps/playground/yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,6 +3104,11 @@ lru-cache@^10.2.0:
31043104
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
31053105
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
31063106

3107+
lru-cache@^11.2.2:
3108+
version "11.2.2"
3109+
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.2.tgz#40fd37edffcfae4b2940379c0722dc6eeaa75f24"
3110+
integrity sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==
3111+
31073112
lru-cache@^5.1.1:
31083113
version "5.1.1"
31093114
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"

0 commit comments

Comments
 (0)