executionId for code re-runs

This commit is contained in:
Vyacheslav Matyukhin 2022-07-27 13:03:23 +04:00
parent 724fb4956d
commit eacc1adf1d
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
4 changed files with 41 additions and 18 deletions

View File

@ -14,6 +14,8 @@ import { SquiggleViewer } from "./SquiggleViewer";
export interface SquiggleChartProps { export interface SquiggleChartProps {
/** The input string for squiggle */ /** The input string for squiggle */
code?: string; code?: string;
/** Allows to re-run the code if code hasn't changed */
executionId?: number;
/** If the output requires monte carlo sampling, the amount of samples */ /** If the output requires monte carlo sampling, the amount of samples */
sampleCount?: number; sampleCount?: number;
/** The amount of points returned to draw the distribution */ /** The amount of points returned to draw the distribution */
@ -59,6 +61,7 @@ const defaultOnChange = () => {};
export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo( export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
({ ({
code = "", code = "",
executionId = 0,
environment, environment,
onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here
height = 200, height = 200,

View File

@ -269,12 +269,19 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
[vars.sampleCount, vars.xyPointLength] [vars.sampleCount, vars.xyPointLength]
); );
const { run, autorunMode, setAutorunMode, isRunning, renderedCode } = const {
useRunnerState(code); run,
autorunMode,
setAutorunMode,
isRunning,
renderedCode,
executionId,
} = useRunnerState(code);
const squiggleChart = ( const squiggleChart = (
<SquiggleChart <SquiggleChart
code={renderedCode} code={renderedCode}
executionId={executionId}
environment={env} environment={env}
{...vars} {...vars}
bindings={defaultBindings} bindings={defaultBindings}

View File

@ -3,15 +3,16 @@ import { useEffect, useReducer } from "react";
type State = { type State = {
autorunMode: boolean; autorunMode: boolean;
renderedCode: string; renderedCode: string;
isRunning: boolean; // "prepared" is for rendering a spinner; "run" for executing squiggle code; then it gets back to "none" on the next render
runningState: "none" | "prepared" | "run";
executionId: number; executionId: number;
}; };
const buildInitialState = (code: string) => ({ const buildInitialState = (code: string): State => ({
autorunMode: true, autorunMode: true,
renderedCode: code, renderedCode: code,
isRunning: false, runningState: "none",
executionId: 0, executionId: 1,
}); });
type Action = type Action =
@ -41,18 +42,19 @@ const reducer = (state: State, action: Action): State => {
case "PREPARE_RUN": case "PREPARE_RUN":
return { return {
...state, ...state,
isRunning: true, runningState: "prepared",
}; };
case "RUN": case "RUN":
return { return {
...state, ...state,
runningState: "run",
renderedCode: action.code, renderedCode: action.code,
executionId: state.executionId + 1, executionId: state.executionId + 1,
}; };
case "STOP_RUN": case "STOP_RUN":
return { return {
...state, ...state,
isRunning: false, runningState: "none",
}; };
} }
}; };
@ -61,21 +63,23 @@ export const useRunnerState = (code: string) => {
const [state, dispatch] = useReducer(reducer, buildInitialState(code)); const [state, dispatch] = useReducer(reducer, buildInitialState(code));
useEffect(() => { useEffect(() => {
if (state.isRunning) { if (state.runningState === "prepared") {
if (state.renderedCode !== code) {
dispatch({ type: "RUN", code }); dispatch({ type: "RUN", code });
} else { } else if (state.runningState === "run") {
dispatch({ type: "STOP_RUN" }); dispatch({ type: "STOP_RUN" });
} }
} }, [state.runningState, code]);
}, [state.isRunning, state.renderedCode, code]);
const run = () => { const run = () => {
// The rest will be handled by dispatches above on following renders, but we need to update the spinner first. // The rest will be handled by dispatches above on following renders, but we need to update the spinner first.
dispatch({ type: "PREPARE_RUN" }); dispatch({ type: "PREPARE_RUN" });
}; };
if (state.autorunMode && state.renderedCode !== code && !state.isRunning) { if (
state.autorunMode &&
state.renderedCode !== code &&
state.runningState === "none"
) {
run(); run();
} }
@ -83,7 +87,7 @@ export const useRunnerState = (code: string) => {
run, run,
autorunMode: state.autorunMode, autorunMode: state.autorunMode,
renderedCode: state.renderedCode, renderedCode: state.renderedCode,
isRunning: state.isRunning, isRunning: state.runningState !== "none",
executionId: state.executionId, executionId: state.executionId,
setAutorunMode: (newValue: boolean) => { setAutorunMode: (newValue: boolean) => {
dispatch({ type: "SET_AUTORUN_MODE", value: newValue, code }); dispatch({ type: "SET_AUTORUN_MODE", value: newValue, code });

View File

@ -9,6 +9,7 @@ import { useEffect, useMemo } from "react";
type SquiggleArgs<T extends ReturnType<typeof run | typeof runPartial>> = { type SquiggleArgs<T extends ReturnType<typeof run | typeof runPartial>> = {
code: string; code: string;
executionId?: number;
bindings?: bindings; bindings?: bindings;
jsImports?: jsImports; jsImports?: jsImports;
environment?: environment; environment?: environment;
@ -21,7 +22,15 @@ const useSquiggleAny = <T extends ReturnType<typeof run | typeof runPartial>>(
) => { ) => {
const result: T = useMemo<T>( const result: T = useMemo<T>(
() => f(args.code, args.bindings, args.environment, args.jsImports), () => f(args.code, args.bindings, args.environment, args.jsImports),
[f, args.code, args.bindings, args.environment, args.jsImports] // eslint-disable-next-line react-hooks/exhaustive-deps
[
f,
args.code,
args.bindings,
args.environment,
args.jsImports,
args.executionId,
]
); );
const { onChange } = args; const { onChange } = args;