Skip to content

Commit e1de1da

Browse files
authored
Merge pull request #3 from theopensystemslab/concurrent
Concurrent prototype
2 parents e9bb33c + 2d2a669 commit e1de1da

File tree

8 files changed

+1216
-1584
lines changed

8 files changed

+1216
-1584
lines changed

package.json

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,27 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6-
"@nx-js/observer-util": "^4.2.2",
76
"@teamwork/websocket-json-stream": "^2.0.0",
8-
"@testing-library/jest-dom": "^4.2.4",
9-
"@testing-library/react": "^9.3.2",
10-
"@testing-library/user-event": "^7.1.2",
117
"@types/jest": "^24.0.0",
128
"@types/node": "^12.0.0",
13-
"@types/react": "^16.9.0",
14-
"@types/react-dom": "^16.9.0",
9+
"@types/react": "^16.9.43",
10+
"@types/react-dom": "^16.9.8",
1511
"@types/uuid": "^8.0.0",
16-
"comlink": "^4.3.0",
1712
"express": "^4.17.1",
18-
"nanoid": "^3.1.10",
1913
"random-words": "^1.1.1",
20-
"react": "^16.13.1",
21-
"react-dom": "^16.13.1",
14+
"react": "^0.0.0-experimental-4c8c98ab9",
15+
"react-dom": "^0.0.0-experimental-4c8c98ab9",
2216
"react-router-dom": "^5.2.0",
2317
"react-scripts": "3.4.1",
24-
"react-use-comlink": "^2.0.1",
2518
"reconnecting-websocket": "^4.4.0",
2619
"sharedb": "^1.4.0",
27-
"typescript": "~3.7.2",
20+
"typescript": "^3.9.7",
2821
"uuid": "^8.2.0",
2922
"ws": "^7.3.1"
3023
},
24+
"devDependencies": {
25+
"concurrently": "^5.2.0"
26+
},
3127
"scripts": {
3228
"start": "concurrently 'node server' 'react-scripts start'",
3329
"build": "react-scripts build",
@@ -48,10 +44,5 @@
4844
"last 1 firefox version",
4945
"last 1 safari version"
5046
]
51-
},
52-
"devDependencies": {
53-
"concurrently": "^5.2.0",
54-
"ts-node": "^8.10.2",
55-
"ts-node-dev": "^1.0.0-pre.52"
5647
}
5748
}

src/App.tsx

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import randomWords from "random-words";
22
import { v4 as uuid } from "uuid";
3-
import React, { useEffect, useMemo } from "react";
3+
import React, { useMemo, useState, useEffect, useCallback } from "react";
44
import { connectToDB, getConnection } from "./sharedb";
5+
import { useTransition } from "./react-experimental";
56
import {
67
Link,
78
BrowserRouter as Router,
@@ -26,16 +27,21 @@ function useFlow(config: {
2627
addNode: () => void;
2728
removeNode: (id: string) => void;
2829
reset: (flow: Flow) => void;
30+
isPending: boolean;
2931
} {
3032
// Setup
3133

32-
const [state, setState] = React.useState<Flow | null>(null);
34+
const [startTransition, isPending] = useTransition();
35+
36+
const [state, setState] = useState<Flow | null>(null);
3337

3438
const doc = useMemo(() => getConnection(config.id), [config.id]);
3539

3640
useEffect(() => {
3741
const cloneStateFromShareDB = () =>
38-
setState(JSON.parse(JSON.stringify(doc.data)));
42+
startTransition(() => {
43+
setState(JSON.parse(JSON.stringify(doc.data)));
44+
});
3945

4046
connectToDB(doc).then(() => {
4147
cloneStateFromShareDB();
@@ -46,22 +52,22 @@ function useFlow(config: {
4652
setState(null);
4753
doc.destroy();
4854
};
49-
}, [doc]);
55+
}, [doc, startTransition]);
5056

5157
// Methods
5258

53-
const addNode = React.useCallback(() => {
59+
const addNode = useCallback(() => {
5460
doc.submitOp([{ p: ["nodes", uuid()], oi: { text: randomWords() } }]);
5561
}, [doc]);
5662

57-
const removeNode = React.useCallback(
63+
const removeNode = useCallback(
5864
(id) => {
5965
doc.submitOp([{ p: ["nodes", id], od: {} }]);
6066
},
6167
[doc]
6268
);
6369

64-
const reset = React.useCallback(
70+
const reset = useCallback(
6571
(flow) => {
6672
doc.submitOp([{ p: [], od: doc.data, oi: flow }]);
6773
},
@@ -75,6 +81,7 @@ function useFlow(config: {
7581
addNode,
7682
removeNode,
7783
reset,
84+
isPending,
7885
};
7986
}
8087

@@ -86,44 +93,47 @@ const Flow: React.FC<{ id: string }> = ({ id }) => {
8693
}
8794

8895
return (
89-
<main>
90-
<button
91-
onClick={() => {
92-
flow.addNode();
93-
}}
94-
>
95-
Add
96-
</button>
97-
<button
98-
onClick={() => {
99-
fetch("/flow.json")
100-
.then((res) => res.json())
101-
.then((flowData) => {
102-
flow.reset(flowData);
96+
<>
97+
<main>
98+
<button
99+
onClick={() => {
100+
flow.addNode();
101+
}}
102+
>
103+
Add
104+
</button>
105+
<button
106+
onClick={() => {
107+
fetch("/flow.json")
108+
.then((res) => res.json())
109+
.then((flowData) => {
110+
flow.reset(flowData);
111+
});
112+
}}
113+
>
114+
Import flow
115+
</button>
116+
<button
117+
onClick={() => {
118+
flow.reset({
119+
nodes: {},
120+
edges: [],
103121
});
104-
}}
105-
>
106-
Import flow
107-
</button>
108-
<button
109-
onClick={() => {
110-
flow.reset({
111-
nodes: {},
112-
edges: [],
113-
});
114-
}}
115-
>
116-
Reset
117-
</button>
118-
{Object.keys(flow.state.nodes).map((k) => (
119-
<NodeView
120-
key={k}
121-
onRemove={flow.removeNode}
122-
id={k}
123-
node={flow.state.nodes[k]}
124-
/>
125-
))}
126-
</main>
122+
}}
123+
>
124+
Reset
125+
</button>
126+
{Object.keys(flow.state.nodes).map((k) => (
127+
<NodeView
128+
key={k}
129+
onRemove={flow.removeNode}
130+
id={k}
131+
node={flow.state.nodes[k]}
132+
/>
133+
))}
134+
</main>
135+
{flow.isPending && <div className="overlay" />}
136+
</>
127137
);
128138
};
129139

@@ -168,7 +178,7 @@ const App = () => {
168178
const history = useHistory();
169179
const location = useLocation();
170180

171-
const id = React.useMemo(() => {
181+
const id = useMemo(() => {
172182
if (location.hash.length < 2) {
173183
return null;
174184
}

src/index.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import React from "react";
2-
import ReactDOM from "react-dom";
2+
import { createRoot } from "./react-experimental";
33
import App from "./App";
44
import * as serviceWorker from "./serviceWorker";
55
import "./style.css";
66

7-
ReactDOM.render(
7+
createRoot(document.getElementById("root")).render(
88
<React.StrictMode>
99
<App />
10-
</React.StrictMode>,
11-
document.getElementById("root")
10+
</React.StrictMode>
1211
);
1312

1413
// If you want your app to work offline and load faster, you can change

src/react-app-env.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
/// <reference types="react-scripts" />
2+
/// <reference types="react-dom/experimental" />
3+
/// <reference types="react/experimental" />

src/react-experimental.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as React from "react";
2+
import * as ReactDOM from "react-dom";
3+
4+
/**
5+
* Typing hacks for experimental concurrent mode features in React
6+
*/
7+
8+
export const createRoot = (ReactDOM as any).unstable_createRoot;
9+
10+
export const useTransition: () => [
11+
(fn: Function) => void,
12+
boolean
13+
] = (React as any).unstable_useTransition;

src/style.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,13 @@ a {
3939
.remove-button:hover {
4040
background-color: #dedede;
4141
}
42+
43+
.overlay {
44+
position: fixed;
45+
top: 0;
46+
left: 0;
47+
right: 0;
48+
bottom: 0;
49+
background-color: rgba(255, 255, 255, 0.6);
50+
z-index: 1000;
51+
}

tsconfig.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
{
22
"compilerOptions": {
33
"target": "es5",
4-
"lib": [
5-
"dom",
6-
"dom.iterable",
7-
"esnext"
8-
],
4+
"lib": ["dom", "dom.iterable", "esnext"],
95
"allowJs": true,
106
"skipLibCheck": true,
117
"esModuleInterop": true,
@@ -19,7 +15,5 @@
1915
"noEmit": true,
2016
"jsx": "react"
2117
},
22-
"include": [
23-
"src"
24-
]
18+
"include": ["src"]
2519
}

0 commit comments

Comments
 (0)