Skip to content

Commit 8407c75

Browse files
authored
perf(SampleDropdown & Store): Memoization & Redundancy fix with Readability & Modularity (#122)
* enhancing readability, and reducing unnecessary re-renders(sampleDropdown) Signed-off-by: nitro56565 <nitro56565@gmail.com> * conditionally rendered template name Signed-off-by: nitro56565 <nitro56565@gmail.com> --------- Signed-off-by: nitro56565 <nitro56565@gmail.com>
1 parent a72513b commit 8407c75

File tree

3 files changed

+67
-54
lines changed

3 files changed

+67
-54
lines changed

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/SampleDropdown.tsx

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,62 @@
1-
import { Button, Dropdown, Space, message } from "antd";
1+
import { Button, Dropdown, Space, message, MenuProps } from "antd";
22
import { DownOutlined } from "@ant-design/icons";
3-
3+
import { memo, useCallback, useMemo, useState } from "react";
44
import useAppStore from "../store/store";
5+
import { shallow } from "zustand/shallow";
56

6-
function SampleDropdown({ setLoading }: { setLoading: any }) {
7-
const samples = useAppStore((state) => state.samples);
8-
const loadSample = useAppStore((state) => state.loadSample);
7+
function SampleDropdown({
8+
setLoading,
9+
}: {
10+
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
11+
}): JSX.Element {
12+
const { samples, loadSample } = useAppStore(
13+
(state) => ({
14+
samples: state.samples,
15+
loadSample: state.loadSample as (key: string) => Promise<void>,
16+
}),
17+
shallow
18+
);
919

10-
const items = samples.map((s) => ({
11-
label: s.NAME,
12-
key: s.NAME,
13-
}));
20+
const [selectedSample, setSelectedSample] = useState<string | null>(null);
1421

15-
const handleMenuClick = async (e: any) => {
16-
if (e.key) {
17-
setLoading(true);
18-
try {
19-
await loadSample(e.key);
20-
message.info(`Loaded ${e.key} sample`);
21-
} catch (error) {
22-
message.error("Failed to load sample");
23-
} finally {
24-
setLoading(false);
25-
}
26-
}
27-
};
22+
const items: MenuProps["items"] = useMemo(
23+
() =>
24+
samples.map((s) => ({
25+
label: s.NAME,
26+
key: s.NAME,
27+
})),
28+
[samples]
29+
);
2830

29-
const menuProps = {
30-
items,
31-
onClick: handleMenuClick,
32-
};
31+
const handleMenuClick = useCallback(
32+
async (e: any) => {
33+
if (e.key) {
34+
setLoading(true);
35+
try {
36+
await loadSample(e.key);
37+
message.info(`Loaded ${e.key} sample`);
38+
setSelectedSample(e.key);
39+
} catch (error) {
40+
message.error("Failed to load sample");
41+
} finally {
42+
setLoading(false);
43+
}
44+
}
45+
},
46+
[loadSample, setLoading]
47+
);
3348

3449
return (
3550
<Space>
36-
<Dropdown menu={menuProps} trigger={["click"]}>
51+
<Dropdown menu={{ items, onClick: handleMenuClick }} trigger={["click"]}>
3752
<div className="samples-element">
3853
<Button>
39-
Load Sample <DownOutlined />
54+
{selectedSample ? selectedSample : "Load Sample"} <DownOutlined />
4055
</Button>
4156
</div>
4257
</Dropdown>
4358
</Space>
4459
);
4560
}
4661

47-
export default SampleDropdown;
62+
export default memo(SampleDropdown);

src/store/store.ts

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export interface DecompressedData {
4444
agreementHtml: string;
4545
}
4646

47+
const rebuildDeBounce = debounce(rebuild, 500);
48+
4749
async function rebuild(template: string, model: string, dataString: string) {
4850
const modelManager = new ModelManager({ strict: true });
4951
modelManager.addCTOModel(model, undefined, true);
@@ -67,8 +69,6 @@ async function rebuild(template: string, model: string, dataString: string) {
6769
);
6870
}
6971

70-
const rebuildDeBounce = debounce(rebuild, 500);
71-
7272
const useAppStore = create<AppState>()(
7373
immer(
7474
devtools((set, get) => ({
@@ -120,45 +120,42 @@ const useAppStore = create<AppState>()(
120120
}
121121
},
122122
rebuild: async () => {
123+
const { templateMarkdown, modelCto, data } = get();
123124
try {
124-
const result = await rebuildDeBounce(
125-
get().templateMarkdown,
126-
get().modelCto,
127-
get().data
128-
);
125+
const result = await rebuildDeBounce(templateMarkdown, modelCto, data);
129126
set(() => ({ agreementHtml: result, error: undefined }));
130127
} catch (error: any) {
131128
set(() => ({ error: formatError(error) }));
132129
}
133130
},
134131
setTemplateMarkdown: async (template: string) => {
132+
const { modelCto, data } = get();
135133
try {
136-
const result = await rebuildDeBounce(
137-
template,
138-
get().modelCto,
139-
get().data
140-
);
141-
set(() => ({ agreementHtml: result, error: undefined }));
134+
const result = await rebuildDeBounce(template, modelCto, data);
135+
set(() => ({
136+
templateMarkdown: template,
137+
agreementHtml: result,
138+
error: undefined,
139+
}));
142140
} catch (error: any) {
143141
set(() => ({ error: formatError(error) }));
144142
}
145-
set(() => ({ templateMarkdown: template }));
146143
},
147144
setEditorValue: (value: string) => {
148145
set(() => ({ editorValue: value }));
149146
},
150147
setModelCto: async (model: string) => {
148+
const { templateMarkdown, data } = get();
151149
try {
152-
const result = await rebuildDeBounce(
153-
get().templateMarkdown,
154-
model,
155-
get().data
156-
);
157-
set(() => ({ agreementHtml: result, error: undefined }));
150+
const result = await rebuildDeBounce(templateMarkdown, model, data);
151+
set(() => ({
152+
modelCto: model,
153+
agreementHtml: result,
154+
error: undefined,
155+
}));
158156
} catch (error: any) {
159157
set(() => ({ error: formatError(error) }));
160158
}
161-
set(() => ({ modelCto: model }));
162159
},
163160
setEditorModelCto: (value: string) => {
164161
set(() => ({ editorModelCto: value }));

0 commit comments

Comments
 (0)