diff --git a/src/libs/scheduler/index.ts b/src/libs/scheduler/index.ts
deleted file mode 100644
index 9faa0c1..0000000
--- a/src/libs/scheduler/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './v1';
\ No newline at end of file
diff --git a/src/pages/SchedulerSamplePage.tsx b/src/pages/SchedulerSamplePage.tsx
index d6e5b91..cf519dd 100644
--- a/src/pages/SchedulerSamplePage.tsx
+++ b/src/pages/SchedulerSamplePage.tsx
@@ -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 (
-
"Scheduler" Sample V0
-
Current selection (by state): {getStore().selected}
-
Current selection (by action): {count}
-
{
- Promise.resolve()
- .then(() => {
- setStore({ selected: 0 });
- setCount(getStore().selected);
- });
- }}
- >
- Select None
-
+
"Scheduler" Sample
+
setVersion(v)}
+ />
+ {version === "V0" && }
+ {version === "V1" && }
+ {version === "V2" && }
);
}
+export default SchedulerSamplePage;
+
+
+
/*
function SchedulerSampleV1() {
const { schedulePostDispatchEvents, queue } = useScheduler("test");
@@ -116,16 +105,3 @@ function SchedulerSampleV2() {
}
*/
-function SchedulerSamplePage() {
- return (
-
-
"Scheduler" Sample
- {/*
-
- */}
-
-
- );
-}
-
-export default SchedulerSamplePage;
diff --git a/src/pages/scheduler/DataProvider.ts b/src/pages/scheduler/DataProvider.ts
new file mode 100644
index 0000000..72cf6c1
--- /dev/null
+++ b/src/pages/scheduler/DataProvider.ts
@@ -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,
+ };
+};
\ No newline at end of file
diff --git a/src/pages/scheduler/RadioButtonGroup.tsx b/src/pages/scheduler/RadioButtonGroup.tsx
new file mode 100644
index 0000000..03ee366
--- /dev/null
+++ b/src/pages/scheduler/RadioButtonGroup.tsx
@@ -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) => (
+
+ {
+ setSelected(ev.target.value);
+ onChange(ev.target.value);
+ }}
+ />
+ {option}
+
+ ));
+}
+
+export default RadioButtonGroup;
diff --git a/src/pages/scheduler/SampleV0.tsx b/src/pages/scheduler/SampleV0.tsx
new file mode 100644
index 0000000..a85ac7d
--- /dev/null
+++ b/src/pages/scheduler/SampleV0.tsx
@@ -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 (
+
+
"Scheduler" Sample V0
+
Current selection (by state): {getData().selected}
+
Current selection (by action): {selected}
+
{
+ // 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
+
+
+ );
+}
+
+export default SampleV0;
\ No newline at end of file
diff --git a/src/pages/scheduler/SampleV1.tsx b/src/pages/scheduler/SampleV1.tsx
new file mode 100644
index 0000000..c0faed0
--- /dev/null
+++ b/src/pages/scheduler/SampleV1.tsx
@@ -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 (
+
+
"Scheduler" Sample V0
+
Current selection (by state): {getData().selected}
+
Current selection (by action): {selected}
+
{
+ 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
+
+
+ );
+}
+
+export default SampleV1;
diff --git a/src/pages/scheduler/SampleV2.tsx b/src/pages/scheduler/SampleV2.tsx
new file mode 100644
index 0000000..6edc44d
--- /dev/null
+++ b/src/pages/scheduler/SampleV2.tsx
@@ -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 (
+
+
"Scheduler" Sample V0
+
Current selection (by state): {getData().selected}
+
Current selection (by action): {selected}
+
{
+ 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
+
+
+ );
+}
+
+export default SampleV2;
diff --git a/src/libs/scheduler/scheduler.md b/src/pages/scheduler/libs/scheduler.md
similarity index 100%
rename from src/libs/scheduler/scheduler.md
rename to src/pages/scheduler/libs/scheduler.md
diff --git a/src/libs/scheduler/v1.ts b/src/pages/scheduler/libs/v1.ts
similarity index 100%
rename from src/libs/scheduler/v1.ts
rename to src/pages/scheduler/libs/v1.ts
diff --git a/src/libs/scheduler/v2.ts b/src/pages/scheduler/libs/v2.ts
similarity index 91%
rename from src/libs/scheduler/v2.ts
rename to src/pages/scheduler/libs/v2.ts
index 41e1221..c06de4a 100644
--- a/src/libs/scheduler/v2.ts
+++ b/src/pages/scheduler/libs/v2.ts
@@ -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.
*/