don't re-compute values on first render (unnecessary, values are part of state)

This commit is contained in:
Joeri Exelmans 2025-05-14 06:46:03 +02:00
parent 174bab79e4
commit 2d0deca127
14 changed files with 274 additions and 115 deletions

View file

@ -1,16 +1,47 @@
import { useEffect, useRef, useState } from 'react';
import { useEffect, useState } from 'react';
import './App.css'
import { Editor, type EditorState } from './Editor'
import { initialEditorState, nonEmptyEditorState, tripleFunctionCallEditorState } from "./configurations";
import { CommandContext } from './CommandContext';
import { EnvContext } from './EnvContext';
import { deserialize, serialize } from './types';
import { extendedEnv } from './EnvContext';
import { useEffectBetter } from './util/use_effect_better';
const commands: [string, string[], string][] = [
["call" , ['c' ], "call" ],
["eval" , ['e','Tab','Enter'], "eval" ],
["transform", ['t', '.' ], "transform" ],
["let" , ['l', '=', 'a' ], "let ... in ..."],
];
const examples: [string, EditorState][] = [
["empty editor", initialEditorState],
["push to list", nonEmptyEditorState],
["function w/ 4 params", tripleFunctionCallEditorState]];
export function App() {
// const [history, setHistory] = useState([initialEditorState]);
// const [history, setHistory] = useState([nonEmptyEditorState]);
const [history, setHistory] = useState([tripleFunctionCallEditorState]);
// const [history, setHistory] = useState([tripleFunctionCallEditorState]);
// const [future, setFuture] = useState<EditorState[]>([]);
const [future, setFuture] = useState<EditorState[]>([]);
// load from localStorage
const [history, setHistory] = useState<EditorState[]>(
localStorage["history"]
? JSON.parse(localStorage["history"]).map(s => deserialize(s, extendedEnv))
: [initialEditorState]
);
const [future, setFuture] = useState<EditorState[]>(
localStorage["future"]
? JSON.parse(localStorage["future"]).map(s => deserialize(s, extendedEnv))
: []
);
useEffectBetter(() => {
// persist accross reloads
localStorage["history"] = JSON.stringify(history.map(serialize));
localStorage["future"] = JSON.stringify(future.map(serialize));
}, [history, future]);
const pushHistory = (callback: (p: EditorState) => EditorState) => {
const newState = callback(history.at(-1)!);
@ -51,12 +82,6 @@ export function App() {
window.onkeydown = onKeyDown;
}, []);
const commands: [string, string[], string][] = [
["call" , ['c' ], "call" ],
["eval" , ['e','Tab','Enter' ], "eval" ],
["transform", ['t', '.' ], "transform" ],
["let" , ['l', '=', 'a' ], "let ... in ..."],
];
const [highlighted, setHighlighted] = useState(
commands.map(() => false));
@ -68,12 +93,16 @@ export function App() {
}];
}));
const onSelectExample = (e: React.SyntheticEvent<HTMLSelectElement>) => {
// @ts-ignore
pushHistory(_ => examples[e.target.value][1]);
}
return (
<>
<header>
<button disabled={history.length===1} onClick={onUndo}>Undo ({history.length-1}) [Ctrl+Z]</button>
<button disabled={future.length===0} onClick={onRedo}>Redo ({future.length}) [Ctrl+Shift+Z]</button>
Commands:
<button disabled={history.length===1} onClick={onUndo}>Undo ({history.length-1}) <kbd>Ctrl</kbd>+<kbd>Z</kbd></button>
<button disabled={future.length===0} onClick={onRedo}>Redo ({future.length}) <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd></button>
{
commands.map(([_, keys, descr], i) =>
<span key={i} className={'command' + (highlighted[i] ? (' highlighted') : '')}>
@ -81,6 +110,17 @@ export function App() {
{descr}
</span>)
}
<select onClick={onSelectExample}>
{
examples.map(([name], i) => {
return <option key={i} value={i}>{name}</option>;
})
}
</select>
<button className="factoryReset" onClick={() => {
setHistory(_ => [initialEditorState]);
setFuture(_ => []);
}}>FACTORY RESET</button>
</header>
<main onKeyDown={onKeyDown}>