From 1ce625f5bcfdb27279de056790dd9510ff899601 Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Thu, 25 Jul 2024 23:53:27 -0500 Subject: [PATCH] Cleaner method for Editor passing methods up --- src/Components/App.tsx | 26 +++++----- src/Components/Editor.tsx | 100 +++++++++++++++++++------------------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/Components/App.tsx b/src/Components/App.tsx index fde031ee..3a473e03 100644 --- a/src/Components/App.tsx +++ b/src/Components/App.tsx @@ -12,7 +12,7 @@ import type { WebRProxyHandle } from "../hooks/useWebR"; import { initRShiny, initWebR, useWebR } from "../hooks/useWebR"; import type { ProxyType } from "../pyodide-proxy"; import "./App.css"; -import { type EditorHandle } from "./Editor"; +import { type EditorMethods } from "./Editor"; import { ExampleSelector } from "./ExampleSelector"; import type { HeaderBarCallbacks } from "./HeaderBar"; import HeaderBar from "./HeaderBar"; @@ -246,6 +246,10 @@ export function App({ const proxyHandle = useWasmEngine(); + const [editorMethods, setEditorMethods] = React.useState({ + getActiveFileContents: null, + }); + const [viewerMethods, setViewerMethods] = React.useState({ ready: false, }); @@ -296,8 +300,6 @@ export function App({ })(); }, [proxyHandle.ready, currentFiles]); - const editorRef = React.useRef(null); - // Set up message listener for communication with parent window. React.useEffect(() => { const listener = (event: MessageEvent) => { @@ -311,8 +313,8 @@ export function App({ } else if (event.data.type === "getFiles") { // Request files from Editor component and send them back to parent. let files: FileContent[] = []; - if (editorRef.current) { - files = editorRef.current.getActiveFileContents(); + if (editorMethods.getActiveFileContents) { + files = editorMethods.getActiveFileContents(); } event.ports[0].postMessage({ files: files }); @@ -322,10 +324,10 @@ export function App({ window.addEventListener("message", listener); // Cleanup function - () => { + return () => { window.removeEventListener("message", listener); }; - }, [currentFiles, setCurrentFiles]); + }, [currentFiles, setCurrentFiles, editorMethods]); const [utilityMethods, setUtilityMethods] = React.useState({ formatCode: async (code: string) => { @@ -393,6 +395,7 @@ export function App({ setCurrentFiles={setCurrentFiles} setFilesHaveChanged={setFilesHaveChanged} setHeaderBarCallbacks={setHeaderBarCallbacks} + setEditorMethods={setEditorMethods} terminalMethods={terminalMethods} viewerMethods={viewerMethods} utilityMethods={utilityMethods} @@ -404,7 +407,6 @@ export function App({ )} updateUrlHashOnRerun={appOptions.updateUrlHashOnRerun} appEngine={appEngine} - ref={editorRef} /> FileContent[]; +export type EditorMethods = { + // This function returns the current contents of the files in the editor. + getActiveFileContents: (() => FileContent[]) | null; }; -const Editor = React.forwardRef(function Editor( - { - currentFilesFromApp, - setCurrentFiles, - setFilesHaveChanged, - setHeaderBarCallbacks, - terminalMethods, - viewerMethods = null, - utilityMethods = null, - showFileTabs = true, - runOnLoad = true, - lineNumbers = true, - showHeaderBar = true, - floatingButtons = false, - updateUrlHashOnRerun = false, - appEngine, - style, - }: { - currentFilesFromApp: FileContent[]; - setCurrentFiles: React.Dispatch>; - setFilesHaveChanged: React.Dispatch>; - setHeaderBarCallbacks: React.Dispatch< - React.SetStateAction - >; - terminalMethods: TerminalMethods; - viewerMethods?: ViewerMethods | null; - utilityMethods?: UtilityMethods | null; - showFileTabs?: boolean; - runOnLoad?: boolean; - lineNumbers?: boolean; - showHeaderBar?: boolean; - floatingButtons?: boolean; - updateUrlHashOnRerun?: boolean; - appEngine: AppEngine; - style?: React.CSSProperties; - }, - ref: React.Ref, -) { +export default function Editor({ + currentFilesFromApp, + setCurrentFiles, + setFilesHaveChanged, + setHeaderBarCallbacks, + setEditorMethods, + terminalMethods, + viewerMethods = null, + utilityMethods = null, + showFileTabs = true, + runOnLoad = true, + lineNumbers = true, + showHeaderBar = true, + floatingButtons = false, + updateUrlHashOnRerun = false, + appEngine, + style, +}: { + currentFilesFromApp: FileContent[]; + setCurrentFiles: React.Dispatch>; + setFilesHaveChanged: React.Dispatch>; + setHeaderBarCallbacks: React.Dispatch< + React.SetStateAction + >; + setEditorMethods: React.Dispatch>; + terminalMethods: TerminalMethods; + viewerMethods?: ViewerMethods | null; + utilityMethods?: UtilityMethods | null; + showFileTabs?: boolean; + runOnLoad?: boolean; + lineNumbers?: boolean; + showHeaderBar?: boolean; + floatingButtons?: boolean; + updateUrlHashOnRerun?: boolean; + appEngine: AppEngine; + style?: React.CSSProperties; +}) { // In the future, instead of directly instantiating the PyrightClient, it // would make sense to abstract it out to a class which in turn can run // multiple language server clients behind the scenes. In this file, @@ -351,14 +351,14 @@ const Editor = React.forwardRef(function Editor( })(); }, [runOnLoad, currentFilesFromApp, terminalMethods, runCodeInTerminal]); - React.useImperativeHandle(ref, () => ({ - getActiveFileContents: () => { - syncActiveFileState(); - const fileContents = editorFilesToFileContents(files); - - return fileContents; - }, - })); + React.useEffect(() => { + setEditorMethods({ + getActiveFileContents: () => { + syncActiveFileState(); + return editorFilesToFileContents(files); + }, + }); + }, [syncActiveFileState, setEditorMethods, files]); // =========================================================================== // CodeMirror setup @@ -669,9 +669,7 @@ const Editor = React.forwardRef(function Editor( ) : null} ); -}); - -export default Editor; +} // ============================================================================= // Conversion between FileContent and EditorFile