Skip to content

Commit

Permalink
working example
Browse files Browse the repository at this point in the history
  • Loading branch information
jesse23 committed Dec 27, 2024
1 parent 04f126f commit d9a82fd
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 45 deletions.
1 change: 0 additions & 1 deletion src/libs/scheduler/index.ts

This file was deleted.

62 changes: 19 additions & 43 deletions src/pages/SchedulerSamplePage.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,29 @@
import { useRef, useState } from "react";

const useStore = (initVal: number) => {
const [state, setState] = useState({ selected: initVal });
const stateRef = useRef({ selected: initVal });
stateRef.current = state;

return {
getStore: () => stateRef.current,
setStore: setState,
};
};

function SchedulerSampleV0() {
const { getStore, setStore } = useStore(6);
const [count, setCount] = useState(getStore().selected);
import { useState } from "react";
import { RadioButtonGroup } from "./scheduler/RadioButtonGroup";
import { SampleV0 } from "./scheduler/SampleV0";
import { SampleV1 } from "./scheduler/SampleV1";
import { SampleV2 } from "./scheduler/SampleV2";

function SchedulerSamplePage() {
const [version, setVersion] = useState("V0");
return (
<div>
<h3>"Scheduler" Sample V0</h3>
<div>Current selection (by state): {getStore().selected}</div>
<div>Current selection (by action): {count}</div>
<button
onClick={() => {
Promise.resolve()
.then(() => {
setStore({ selected: 0 });
setCount(getStore().selected);
});
}}
>
Select None
</button>
<h1>"Scheduler" Sample</h1>
<RadioButtonGroup
options={["V0", "V1", "V2"]}
onChange={(v: string) => setVersion(v)}
/>
{version === "V0" && <SampleV0 />}
{version === "V1" && <SampleV1 />}
{version === "V2" && <SampleV2 />}
</div>
);
}

export default SchedulerSamplePage;



/*
function SchedulerSampleV1() {
const { schedulePostDispatchEvents, queue } = useScheduler("test");
Expand Down Expand Up @@ -116,16 +105,3 @@ function SchedulerSampleV2() {
}
*/

function SchedulerSamplePage() {
return (
<div>
<h1>"Scheduler" Sample</h1>
{/*
<SchedulerSampleV0 />
*/}
<SchedulerSampleV0 />
</div>
);
}

export default SchedulerSamplePage;
18 changes: 18 additions & 0 deletions src/pages/scheduler/DataProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useRef, useState } from "react";

interface DataProvider {
selected: number;
}

export const useDataProvider = (initVal: DataProvider) => {
const stateRef = useRef(initVal);
const [state, setState] = useState(initVal);

// wrong impl to mimic react state update side effect
stateRef.current = state;

return {
getData: () => stateRef.current,
setData: setState,
};
};
27 changes: 27 additions & 0 deletions src/pages/scheduler/RadioButtonGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useState } from "react";

export function RadioButtonGroup({
options,
onChange,
}: {
options: string[];
onChange: (option: string) => void;
}) {
const [selected, setSelected] = useState(options[0]);
return options.map((option) => (
<label key={option}>
<input
type="radio"
value={option}
checked={selected === option}
onChange={(ev) => {
setSelected(ev.target.value);
onChange(ev.target.value);
}}
/>
{option}
</label>
));
}

export default RadioButtonGroup;
36 changes: 36 additions & 0 deletions src/pages/scheduler/SampleV0.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useState } from "react";
import { useDataProvider } from "./DataProvider";



export function SampleV0() {
const { getData, setData } = useDataProvider({ selected: 6 });
const [selected, setSelected] = useState(getData().selected);

return (
<div>
<h3>"Scheduler" Sample V0</h3>
<div>Current selection (by state): {getData().selected}</div>
<div>Current selection (by action): {selected}</div>
<button
onClick={() => {
// r17
// - all setState will be executed immediately
// r18 compatible mode
// - setState in sync mode will be batched
// - setState in async mode will be executed immediately
// r18 concurrent mode
// - all setState will be batched
Promise.resolve().then(() => {
setData({ selected: 0 });
setSelected(getData().selected);
});
}}
>
Select None
</button>
</div>
);
}

export default SampleV0;
45 changes: 45 additions & 0 deletions src/pages/scheduler/SampleV1.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useState } from "react";
import { useDataProvider } from "./DataProvider";
import { useProcessJobQueue, useScheduler } from "./libs/v1";

export function SampleV1() {
const { getData, setData } = useDataProvider({ selected: 6 });
const [selected, setSelected] = useState(getData().selected);
const { schedulePostDispatchEvents, queue } = useScheduler("test");

useProcessJobQueue(queue, "test");

return (
<div>
<h3>"Scheduler" Sample V0</h3>
<div>Current selection (by state): {getData().selected}</div>
<div>Current selection (by action): {selected}</div>
<button
onClick={() => {
Promise.resolve().then(() => {
setData({ selected: 0 });
schedulePostDispatchEvents({
execute: () => {
setSelected(getData().selected);
},
});
});
// issue for v1: this schedule will not be executed
setTimeout(
() =>
schedulePostDispatchEvents({
execute: () => {
console.log("Job2 (schedule in use effect) executed");
},
}),
2000
);
}}
>
Select None
</button>
</div>
);
}

export default SampleV1;
43 changes: 43 additions & 0 deletions src/pages/scheduler/SampleV2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useState } from "react";
import { useDataProvider } from "./DataProvider";
import { useDeferJobQueue } from "./libs/v2";

export function SampleV2() {
const { getData, setData } = useDataProvider({ selected: 6 });
const [selected, setSelected] = useState(getData().selected);
const { defer } = useDeferJobQueue();

return (
<div>
<h3>"Scheduler" Sample V0</h3>
<div>Current selection (by state): {getData().selected}</div>
<div>Current selection (by action): {selected}</div>
<button
onClick={() => {
Promise.resolve().then(() => {
setData({ selected: 0 });
defer({
execute: () => {
setSelected(getData().selected);
},
});
});
// issue for v1: this schedule will not be executed
setTimeout(
() =>
defer({
execute: () => {
console.log("Job2 (schedule in use effect) executed");
},
}),
2000
);
}}
>
Select None
</button>
</div>
);
}

export default SampleV2;
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion src/libs/scheduler/v2.ts → src/pages/scheduler/libs/v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ interface Job {
* A hook to defer tasks until next state update.
*
* - Task could be sync or async, but it will be just simply triggered.
* - Task could be added by sync or async, but it will be executed in the next state update, and the order is not guaranteed.
* - Task could be added by sync or async, but it will be executed in the next state update, and the order is not guaranteed especially for the task added by async.
*
*
* @returns {Function} defer - A function to defer a callback.
*/
Expand Down

0 comments on commit d9a82fd

Please sign in to comment.