Skip to content

Commit 6dee0cd

Browse files
committed
Merge branch 'ImedAdel-master'
2 parents 14e21b7 + add0267 commit 6dee0cd

File tree

8 files changed

+12106
-2956
lines changed

8 files changed

+12106
-2956
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>React Hooks</title>
6+
<link href="/css/currentStyle.css" rel="stylesheet"/>
7+
</head>
8+
<body>
9+
<div id='main'></div>
10+
<script src='dist/main.js'></script>
11+
</body>
12+
</html>

frameworks/keyed/react-zustand/package-lock.json

Lines changed: 11673 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "js-framework-benchmark-react-zustand",
3+
"version": "1.2.0",
4+
"description": "React Zustand demo",
5+
"main": "index.js",
6+
"js-framework-benchmark": {
7+
"frameworkVersionFromPackage": "react:zustand"
8+
},
9+
"scripts": {
10+
"build-dev": "webpack --watch",
11+
"build-prod": "webpack"
12+
},
13+
"keywords": [
14+
"react",
15+
"webpack"
16+
],
17+
"author": "Stefan Krause",
18+
"license": "Apache-2.0",
19+
"homepage": "https://github.com/krausest/js-framework-benchmark",
20+
"repository": {
21+
"type": "git",
22+
"url": "https://github.com/krausest/js-framework-benchmark.git"
23+
},
24+
"devDependencies": {
25+
"@babel/core": "7.12.3",
26+
"@babel/preset-env": "7.12.1",
27+
"@babel/preset-react": "7.12.1",
28+
"babel-loader": "8.1.0",
29+
"terser-webpack-plugin": "1.3.0",
30+
"webpack": "4.34.0",
31+
"webpack-cli": "3.3.4"
32+
},
33+
"dependencies": {
34+
"react": "17.0.1",
35+
"react-dom": "17.0.1",
36+
"zustand": "^3.6.7"
37+
}
38+
}
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
import { memo, useCallback } from "react"
2+
import { render } from "react-dom"
3+
import create from "zustand"
4+
import shallow from "zustand/shallow"
5+
6+
const useStore = create((set) => ({
7+
data: [],
8+
selected: null,
9+
run: () => set({ data: buildData(1000) }),
10+
runLots: () => set({ data: buildData(10000) }),
11+
add: () => set((state) => ({ data: [...state.data, ...buildData(1000)] })),
12+
update: () =>
13+
set((state) => {
14+
let newData = state.data.slice(0)
15+
for (let i = 0, len = newData.length; i < len; i += 10) {
16+
const r = newData[i]
17+
18+
newData[i] = { id: r.id, label: r.label + " !!!" }
19+
}
20+
21+
return { data: newData }
22+
}),
23+
clear: () => set({ data: [] }),
24+
swapRows: () =>
25+
set((state) => {
26+
const d = state.data.slice(0)
27+
if (d.length > 998) {
28+
let tmp = d[1]
29+
d[1] = d[998]
30+
d[998] = tmp
31+
return { data: d }
32+
}
33+
}),
34+
remove: (id) =>
35+
set((state) => {
36+
const idx = state.data.findIndex((d) => d.id === id)
37+
return {
38+
data: [...state.data.slice(0, idx), ...state.data.slice(idx + 1)],
39+
}
40+
}),
41+
select: (id) => set({ selected: id }),
42+
}))
43+
44+
const random = (max) => Math.round(Math.random() * 1000) % max
45+
46+
const A = [
47+
"pretty",
48+
"large",
49+
"big",
50+
"small",
51+
"tall",
52+
"short",
53+
"long",
54+
"handsome",
55+
"plain",
56+
"quaint",
57+
"clean",
58+
"elegant",
59+
"easy",
60+
"angry",
61+
"crazy",
62+
"helpful",
63+
"mushy",
64+
"odd",
65+
"unsightly",
66+
"adorable",
67+
"important",
68+
"inexpensive",
69+
"cheap",
70+
"expensive",
71+
"fancy",
72+
]
73+
const C = [
74+
"red",
75+
"yellow",
76+
"blue",
77+
"green",
78+
"pink",
79+
"brown",
80+
"purple",
81+
"brown",
82+
"white",
83+
"black",
84+
"orange",
85+
]
86+
const N = [
87+
"table",
88+
"chair",
89+
"house",
90+
"bbq",
91+
"desk",
92+
"car",
93+
"pony",
94+
"cookie",
95+
"sandwich",
96+
"burger",
97+
"pizza",
98+
"mouse",
99+
"keyboard",
100+
]
101+
102+
let nextId = 1
103+
104+
const buildData = (count) => {
105+
const data = new Array(count)
106+
107+
for (let i = 0; i < count; i++) {
108+
data[i] = {
109+
id: nextId++,
110+
label: `${A[random(A.length)]} ${C[random(C.length)]} ${
111+
N[random(N.length)]
112+
}`,
113+
}
114+
}
115+
116+
return data
117+
}
118+
119+
const getSelect = (state) => state.select
120+
const getRemove = (state) => state.remove
121+
122+
const Row = memo(
123+
({ itemId }) => {
124+
const select = useStore(getSelect)
125+
const remove = useStore(getRemove)
126+
const itemLabel = useStore(
127+
useCallback(
128+
(state) => state.data.find((item) => item.id === itemId).label,
129+
[itemId]
130+
)
131+
)
132+
const isSelected = useStore(
133+
useCallback((state) => state.selected === itemId, [itemId])
134+
)
135+
136+
return (
137+
<tr className={isSelected ? "danger" : ""}>
138+
<td className="col-md-1">{itemId}</td>
139+
<td className="col-md-4">
140+
<a onClick={() => select(itemId)}>{itemLabel}</a>
141+
</td>
142+
<td className="col-md-1">
143+
<a onClick={() => remove(itemId)}>
144+
<span className="glyphicon glyphicon-remove" aria-hidden="true" />
145+
</a>
146+
</td>
147+
<td className="col-md-6" />
148+
</tr>
149+
)
150+
},
151+
(prevProps, nextProps) => prevProps.itemId === nextProps.itemId
152+
)
153+
154+
const Button = ({ id, cb, title }) => (
155+
<div className="col-sm-6 smallpad">
156+
<button
157+
type="button"
158+
className="btn btn-primary btn-block"
159+
id={id}
160+
onClick={cb}
161+
>
162+
{title}
163+
</button>
164+
</div>
165+
)
166+
167+
const getRun = (state) => state.run
168+
const getRunLots = (state) => state.runLots
169+
const getAdd = (state) => state.add
170+
const getUpdate = (state) => state.update
171+
const getClear = (state) => state.clear
172+
const getSwapRows = (state) => state.swapRows
173+
174+
const Jumbotron = memo(
175+
() => {
176+
const run = useStore(getRun)
177+
const runLots = useStore(getRunLots)
178+
const add = useStore(getAdd)
179+
const update = useStore(getUpdate)
180+
const clear = useStore(getClear)
181+
const swapRows = useStore(getSwapRows)
182+
183+
return (
184+
<div className="jumbotron">
185+
<div className="row">
186+
<div className="col-md-6">
187+
<h1>React Zustand keyed</h1>
188+
</div>
189+
<div className="col-md-6">
190+
<div className="row">
191+
<Button id="run" title="Create 1,000 rows" cb={() => run()} />
192+
<Button
193+
id="runlots"
194+
title="Create 10,000 rows"
195+
cb={() => runLots()}
196+
/>
197+
<Button id="add" title="Append 1,000 rows" cb={() => add()} />
198+
<Button
199+
id="update"
200+
title="Update every 10th row"
201+
cb={() => update()}
202+
/>
203+
<Button id="clear" title="Clear" cb={() => clear()} />
204+
<Button id="swaprows" title="Swap Rows" cb={() => swapRows()} />
205+
</div>
206+
</div>
207+
</div>
208+
</div>
209+
)
210+
},
211+
() => true
212+
)
213+
214+
const getIds = (state) => state.data.map((el) => el.id)
215+
216+
const Main = () => {
217+
/**
218+
* @type {string[]}
219+
*/
220+
const ids = useStore(getIds, shallow)
221+
222+
return (
223+
<div className="container">
224+
<Jumbotron />
225+
<table className="table table-hover table-striped test-data">
226+
<tbody>
227+
{ids.map((id, i) => (
228+
<Row key={id} itemId={id} />
229+
))}
230+
</tbody>
231+
</table>
232+
<span
233+
className="preloadicon glyphicon glyphicon-remove"
234+
aria-hidden="true"
235+
/>
236+
</div>
237+
)
238+
}
239+
240+
render(<Main />, document.getElementById("main"))
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
const path = require('path');
2+
const webpack = require('webpack');
3+
const TerserPlugin = require('terser-webpack-plugin');
4+
5+
module.exports = {
6+
mode: 'production',
7+
// mode: 'development',
8+
entry: {
9+
main: path.join(__dirname, 'src', 'main.jsx'),
10+
},
11+
output: {
12+
path: path.join(__dirname, 'dist'),
13+
filename: '[name].js'
14+
},
15+
resolve: {
16+
extensions: ['.js', '.jsx']
17+
},
18+
module: {
19+
rules: [{
20+
test: /\.jsx?$/,
21+
exclude: /node_modules/,
22+
use: [
23+
{
24+
loader: 'babel-loader',
25+
options: {
26+
presets: ['@babel/preset-env', ['@babel/preset-react', { runtime: 'automatic' }]],
27+
}
28+
}
29+
]
30+
}]
31+
},
32+
optimization: {
33+
minimizer: [
34+
new TerserPlugin({
35+
terserOptions: {
36+
parse: {
37+
// we want terser to parse ecma 8 code. However, we don't want it
38+
// to apply any minfication steps that turns valid ecma 5 code
39+
// into invalid ecma 5 code. This is why the 'compress' and 'output'
40+
// sections only apply transformations that are ecma 5 safe
41+
// https://github.com/facebook/create-react-app/pull/4234
42+
ecma: 8,
43+
},
44+
compress: {
45+
ecma: 5,
46+
warnings: false,
47+
// Disabled because of an issue with Uglify breaking seemingly valid code:
48+
// https://github.com/facebook/create-react-app/issues/2376
49+
// Pending further investigation:
50+
// https://github.com/mishoo/UglifyJS2/issues/2011
51+
comparisons: false,
52+
},
53+
mangle: {
54+
safari10: true,
55+
},
56+
output: {
57+
ecma: 5,
58+
comments: false,
59+
// Turned on because emoji and regex is not minified properly using default
60+
// https://github.com/facebook/create-react-app/issues/2488
61+
ascii_only: true,
62+
},
63+
},
64+
// Use multi-process parallel running to improve the build speed
65+
// Default number of concurrent runs: os.cpus().length - 1
66+
parallel: true,
67+
// Enable file caching
68+
cache: true,
69+
}),
70+
]
71+
},
72+
plugins: [
73+
new webpack.DefinePlugin({
74+
'process.env': { NODE_ENV: JSON.stringify('production') }
75+
}),
76+
],
77+
};

0 commit comments

Comments
 (0)