Skip to content

Commit 76c0a2b

Browse files
committed
Port deeptree-nested scenario
1 parent 3afd06a commit 76c0a2b

File tree

6 files changed

+349
-0
lines changed

6 files changed

+349
-0
lines changed

src/scenarios/deeptree-nested/App.jsx

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from "react";
2+
import { connect } from "react-redux";
3+
4+
import Slice from "./Slice";
5+
import * as c from "./constants";
6+
import { incrementMany, incrementRandomCounter } from "./counters";
7+
import { appendRandomCharacter, appendRandomCharToMany } from "./strings";
8+
9+
let slices;
10+
11+
const mapState = state => {
12+
if (!slices) {
13+
slices = Array.from({ length: c.NUMBER_OF_SLICES }).map(
14+
(dummy, idx) => idx
15+
);
16+
//slices.sort();
17+
}
18+
19+
return { slices };
20+
};
21+
22+
function doUpdateMany(mod) {
23+
return incrementMany({ mod });
24+
}
25+
26+
const mapDispatch = {
27+
incrementRandomCounter,
28+
incrementFifth: () => doUpdateMany(5),
29+
incrementThird: () => doUpdateMany(3),
30+
appendRandomCharacter,
31+
appendMany: () => appendRandomCharToMany(4)
32+
};
33+
34+
class App extends React.Component {
35+
render() {
36+
return (
37+
<div>
38+
<div>
39+
<button
40+
id="incrementRandom"
41+
onClick={this.props.incrementRandomCounter}
42+
>
43+
Update Random Counter
44+
</button>
45+
<button id="incrementFifth" onClick={this.props.incrementFifth}>
46+
Update 1/5 Counters
47+
</button>
48+
<button id="incrementThird" onClick={this.props.incrementThird}>
49+
Update 1/3 Counters
50+
</button>
51+
<button
52+
id="appendRandomCharacter"
53+
onClick={this.props.appendRandomCharacter}
54+
>
55+
Append Random Char
56+
</button>
57+
<button id="appendMany" onClick={this.props.appendMany}>
58+
Append Char to Many
59+
</button>
60+
</div>
61+
<div className="row">
62+
{this.props.slices.map((slice, idx) => {
63+
return (
64+
<div style={{ display: "inline-block", minWidth: 70 }} key={idx}>
65+
<Slice idx={slice} remainingDepth={c.TREE_DEPTH} />
66+
</div>
67+
);
68+
})}
69+
</div>
70+
</div>
71+
);
72+
}
73+
}
74+
App.displayName = "App";
75+
76+
export default connect(
77+
mapState,
78+
mapDispatch
79+
)(App);
+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React, { Component } from "react";
2+
import { connect } from "react-redux";
3+
4+
import { initialize, createStringId } from "./strings";
5+
import { TEXT_INPUT_MOD } from "./constants";
6+
7+
const counterMapState = (state, props) => {
8+
return {
9+
value: state.counters[props.idx]
10+
};
11+
};
12+
13+
const Counter = ({ value }) => {
14+
return <div>Value: {value}</div>;
15+
};
16+
17+
Counter.displayName = "Counter";
18+
19+
const ConnectedCounter = connect(counterMapState)(Counter);
20+
21+
const textMapState = (state, ownProps) => {
22+
const stringId = createStringId(ownProps.idx, ownProps.inputId); //`${ownProps.idx}-${ownProps.remainingDepth}`;
23+
const text = state.strings[stringId] || "unknown";
24+
25+
return { text, stringId };
26+
};
27+
28+
const textMapDispatch = { initialize };
29+
30+
class TextDisplay extends Component {
31+
componentDidMount() {
32+
const { stringId } = this.props;
33+
this.props.initialize({ stringId });
34+
}
35+
36+
render() {
37+
const { text, stringId, children } = this.props;
38+
39+
return (
40+
<div>
41+
Text {stringId}:<br />
42+
<textarea value={text} />
43+
{children}
44+
</div>
45+
);
46+
}
47+
}
48+
TextDisplay.displayName = "TextDisplay";
49+
50+
const ConnectedTextDisplay = connect(
51+
textMapState,
52+
textMapDispatch
53+
)(TextDisplay);
54+
55+
class Slice extends Component {
56+
state = {};
57+
58+
componentDidMount = () => {
59+
//this.props.fillPairs(this.props.idx);
60+
};
61+
62+
render() {
63+
const { remainingDepth, idx } = this.props;
64+
65+
if (remainingDepth > 0) {
66+
let renderedChild = (
67+
<div>
68+
{idx}.{remainingDepth}
69+
<div>
70+
<Slice idx={idx} remainingDepth={remainingDepth - 1} />
71+
</div>
72+
</div>
73+
);
74+
75+
if (remainingDepth % TEXT_INPUT_MOD === 0) {
76+
renderedChild = (
77+
<ConnectedTextDisplay
78+
idx={idx}
79+
inputId={remainingDepth / TEXT_INPUT_MOD}
80+
>
81+
{renderedChild}
82+
</ConnectedTextDisplay>
83+
);
84+
}
85+
86+
return renderedChild;
87+
}
88+
89+
return <ConnectedCounter idx={idx} />;
90+
}
91+
}
92+
Slice.displayName = "Slice";
93+
94+
export default Slice;
95+
//export default connect(mapStateToProps, actions)(Slice);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const NUMBER_OF_SLICES = 200;
2+
3+
export const TREE_DEPTH = 15;
4+
5+
export const TEXT_INPUT_MOD = 5;
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { createSlice } from '@reduxjs/toolkit'
2+
import * as c from './constants'
3+
4+
const { reducer, actions } = createSlice({
5+
name: 'counters',
6+
initialState: {},
7+
reducers: {
8+
initialize(state, action) {
9+
const { numberOfCounters } = action.payload
10+
for (let i = 0; i < numberOfCounters; i++) {
11+
state[i] = 0
12+
}
13+
},
14+
increment(state, action) {
15+
const { counterId } = action.payload
16+
const value = state[counterId] || 0
17+
state[counterId] = value + 1
18+
},
19+
incrementMany(state, action) {
20+
const { mod } = action.payload
21+
for (let counterId = 0; counterId < c.NUMBER_OF_SLICES; counterId++) {
22+
if (counterId % mod === 0) {
23+
const value = state[counterId] || 0
24+
state[counterId] = value + 1
25+
}
26+
}
27+
},
28+
},
29+
})
30+
31+
export const { initialize, increment, incrementMany } = actions
32+
33+
export function incrementRandomCounter() {
34+
const counterId = Math.floor(Math.random() * c.NUMBER_OF_SLICES)
35+
return increment({ counterId })
36+
}
37+
38+
export default reducer
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { useLayoutEffect } from 'react'
2+
import ReactDOM from 'react-dom'
3+
import { configureStore, AnyAction } from '@reduxjs/toolkit'
4+
5+
import { renderApp } from '../../common'
6+
7+
import App from './App'
8+
import * as c from './constants'
9+
import countersReducer, { initialize } from './counters'
10+
import stringsReducer from './strings'
11+
12+
const store = configureStore({
13+
reducer: {
14+
counters: countersReducer,
15+
strings: stringsReducer,
16+
},
17+
middleware: (gdm) =>
18+
gdm({
19+
immutabilityCheck: false,
20+
serializableCheck: false,
21+
}),
22+
})
23+
24+
store.dispatch(initialize({ numberOfCounters: c.NUMBER_OF_SLICES }))
25+
26+
function clickButton(id) {
27+
const element = document.getElementById(id)
28+
29+
if (element) {
30+
element.click()
31+
}
32+
}
33+
34+
const MULTIPLIER = 2
35+
36+
const DeepTreeNestedApp = () => {
37+
useLayoutEffect(() => {
38+
setInterval(() => clickButton('incrementRandom'), 13 * MULTIPLIER)
39+
setInterval(() => clickButton('appendRandomCharacter'), 37 * MULTIPLIER)
40+
setInterval(() => clickButton('incrementFifth'), 103 * MULTIPLIER)
41+
setInterval(() => clickButton('incrementThird'), 193 * MULTIPLIER)
42+
setInterval(() => clickButton('appendMany'), 251 * MULTIPLIER)
43+
}, [])
44+
45+
return <App />
46+
}
47+
48+
// @ts-ignore
49+
renderApp(DeepTreeNestedApp, store)
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { createSlice } from '@reduxjs/toolkit'
2+
import * as c from './constants'
3+
4+
import { TEXT_INPUT_MOD, TREE_DEPTH } from './constants'
5+
6+
const { reducer, actions } = createSlice({
7+
name: 'strings',
8+
initialState: {},
9+
reducers: {
10+
initialize(state, action) {
11+
const { stringId } = action.payload
12+
state[stringId] = 'a'
13+
},
14+
append(state, action) {
15+
const { stringId, character } = action.payload
16+
17+
if (state[stringId]) {
18+
state[stringId] += character
19+
}
20+
//const value = state[counterId] || 0;
21+
//state[counterId] = value + 1;
22+
},
23+
appendMany(state, action) {
24+
const { mod, character } = action.payload
25+
const keys = Object.keys(state)
26+
27+
keys.forEach((stringId, index) => {
28+
if (index % mod === 0) {
29+
state[stringId] += character
30+
}
31+
})
32+
for (let counterId = 0; counterId < c.NUMBER_OF_SLICES; counterId++) {
33+
if (counterId % mod === 0) {
34+
const value = state[counterId] || 0
35+
state[counterId] = value + 1
36+
}
37+
}
38+
},
39+
},
40+
})
41+
42+
export const { initialize, append, appendMany } = actions
43+
44+
const CHARACTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
45+
let nextCharCounter = 0
46+
47+
export function createStringId(sliceId, depth) {
48+
const stringId = `${sliceId}-${depth}`
49+
return stringId
50+
}
51+
52+
function getNextCharacter() {
53+
const charIndex = nextCharCounter % CHARACTERS.length
54+
nextCharCounter++
55+
const character = CHARACTERS.charAt(charIndex)
56+
return character
57+
}
58+
59+
function getRandomInt(min, max) {
60+
min = Math.ceil(min)
61+
max = Math.floor(max)
62+
return Math.floor(Math.random() * (max - min + 1)) + min
63+
}
64+
65+
export function appendRandomCharacter() {
66+
const sliceId = getRandomInt(0, c.NUMBER_OF_SLICES)
67+
const maxTextsPerSlice = Math.floor(TREE_DEPTH / TEXT_INPUT_MOD)
68+
const selectedTextId = getRandomInt(1, maxTextsPerSlice)
69+
70+
const character = getNextCharacter()
71+
72+
const stringId = createStringId(sliceId, selectedTextId)
73+
74+
return append({ stringId, character })
75+
}
76+
77+
export function appendRandomCharToMany(mod) {
78+
const character = getNextCharacter()
79+
80+
return appendMany({ mod, character })
81+
}
82+
83+
export default reducer

0 commit comments

Comments
 (0)