A tool for people curious about the React Server Components protocol rscexplorer.dev/
rsc react

suppress or solve existing issues

some of these might have better solutions

+29 -22
+2 -1
src/client/ui/App.jsx
··· 94 94 const textareaRef = useRef(null); 95 95 const [copied, setCopied] = useState(false); 96 96 97 - const embedCode = useMemo(() => { 97 + const [embedCode] = useState(() => { 98 98 const base = window.location.origin + window.location.pathname.replace(/\/$/, ""); 99 99 const id = Math.random().toString(36).slice(2, 6); 100 100 return `<div id="rsc-${id}" style="height: 500px;"></div> ··· 179 179 }, [workspaceCode]); 180 180 181 181 useEffect(() => { 182 + // eslint-disable-next-line react-hooks/set-state-in-effect 182 183 setLiveCode(workspaceCode); 183 184 if (iframeRef.current?.contentWindow) { 184 185 iframeRef.current.contentWindow.postMessage(
+4 -3
src/client/ui/CodeEditor.jsx
··· 1 - import React, { useRef, useEffect, useEffectEvent } from "react"; 1 + import React, { useRef, useEffect, useEffectEvent, useState } from "react"; 2 2 import { EditorView, keymap } from "@codemirror/view"; 3 3 import { javascript } from "@codemirror/lang-javascript"; 4 4 import { syntaxHighlighting, HighlightStyle } from "@codemirror/language"; ··· 41 41 ); 42 42 43 43 export function CodeEditor({ defaultValue, onChange, label }) { 44 + const [initialDefaultValue] = useState(defaultValue); 44 45 const containerRef = useRef(null); 45 46 46 47 const onEditorChange = useEffectEvent((doc) => { ··· 57 58 }); 58 59 59 60 const editor = new EditorView({ 60 - doc: defaultValue, 61 + doc: initialDefaultValue, 61 62 extensions: [ 62 63 minimalTheme, 63 64 syntaxHighlighting(highlightStyle), ··· 71 72 }); 72 73 73 74 return () => editor.destroy(); 74 - }, []); 75 + }, [initialDefaultValue]); 75 76 76 77 return ( 77 78 <div className="pane">
+21 -18
src/client/ui/FlightLog.jsx
··· 172 172 ); 173 173 } 174 174 175 + const getChunkCount = (entry) => timeline.getChunkCount(entry); 176 + 177 + const entryElements = []; 175 178 let chunkOffset = 0; 176 - const getChunkCount = (entry) => timeline.getChunkCount(entry); 179 + for (let i = 0; i < entries.length; i++) { 180 + const entry = entries[i]; 181 + const chunkStart = chunkOffset; 182 + chunkOffset += getChunkCount(entry); 183 + entryElements.push( 184 + <FlightLogEntry 185 + key={i} 186 + entry={entry} 187 + entryIndex={i} 188 + chunkStart={chunkStart} 189 + cursor={cursor} 190 + canDelete={timeline.canDeleteEntry(i)} 191 + onDelete={onDeleteEntry} 192 + getChunkCount={getChunkCount} 193 + />, 194 + ); 195 + } 177 196 178 197 return ( 179 198 <div className="flight-log" ref={logRef}> 180 - {entries.map((entry, i) => { 181 - const chunkStart = chunkOffset; 182 - chunkOffset += getChunkCount(entry); 183 - 184 - return ( 185 - <FlightLogEntry 186 - key={i} 187 - entry={entry} 188 - entryIndex={i} 189 - chunkStart={chunkStart} 190 - cursor={cursor} 191 - canDelete={timeline.canDeleteEntry(i)} 192 - onDelete={onDeleteEntry} 193 - getChunkCount={getChunkCount} 194 - /> 195 - ); 196 - })} 199 + {entryElements} 197 200 {availableActions.length > 0 && 198 201 (showRawInput ? ( 199 202 <div className="raw-input-form">
+2
src/client/ui/LivePreview.jsx
··· 46 46 47 47 useEffect(() => { 48 48 if (!isPlaying || isAtEnd) { 49 + // eslint-disable-next-line react-hooks/set-state-in-effect 49 50 if (isAtEnd) setIsPlaying(false); 50 51 return; 51 52 } ··· 54 55 }, [isPlaying, isAtEnd, onStep, cursor]); 55 56 56 57 useEffect(() => { 58 + // eslint-disable-next-line react-hooks/set-state-in-effect 57 59 setIsPlaying(false); 58 60 }, [totalChunks]); 59 61