From 61431893bf7a29b2a4f69668927a31ef34eedc98 Mon Sep 17 00:00:00 2001 From: codetypes Date: Thu, 13 Mar 2025 12:54:51 +0800 Subject: [PATCH] use 'useShallow' to optimize selector --- src/components/editor.tsx | 21 +++++++++++-------- src/components/explorer.tsx | 25 ++++++++++++---------- src/components/inspector.tsx | 40 +++++++++++++++++++++--------------- src/components/menu.tsx | 29 ++++++++++++++------------ src/components/titlebar.tsx | 25 ++++++++++++---------- src/components/workspace.tsx | 38 +++++++++++++++++----------------- 6 files changed, 99 insertions(+), 79 deletions(-) diff --git a/src/components/editor.tsx b/src/components/editor.tsx index c8e912a..d3e1c5a 100644 --- a/src/components/editor.tsx +++ b/src/components/editor.tsx @@ -13,6 +13,7 @@ import { RiFocus3Line } from "react-icons/ri"; import { VscCaseSensitive } from "react-icons/vsc"; import { mergeRefs } from "react-merge-refs"; import { useDebounceCallback } from "usehooks-ts"; +import { useShallow } from "zustand/react/shallow"; import { EditEvent, EditNode, @@ -161,15 +162,17 @@ const createMenu = () => { }; export const Editor: FC = ({ onUpdate: updateState, data: editor, ...props }) => { - const workspace = { - editing: useWorkspace((state) => state.editing), - onEditingNode: useWorkspace((state) => state.onEditingNode), - onEditingTree: useWorkspace((state) => state.onEditingTree), - open: useWorkspace((state) => state.open), - workdir: useWorkspace((state) => state.workdir), - relative: useWorkspace((state) => state.relative), - updateFileMeta: useWorkspace((state) => state.updateFileMeta), - }; + const workspace = useWorkspace( + useShallow((state) => ({ + editing: state.editing, + onEditingNode: state.onEditingNode, + onEditingTree: state.onEditingTree, + open: state.open, + workdir: state.workdir, + relative: state.relative, + updateFileMeta: state.updateFileMeta, + })) + ); const searchInputRef = useRef(null); const graphRef = useRef(null); diff --git a/src/components/explorer.tsx b/src/components/explorer.tsx index cca8d5a..f693634 100644 --- a/src/components/explorer.tsx +++ b/src/components/explorer.tsx @@ -10,6 +10,7 @@ import { FaExclamationTriangle, FaSwatchbook } from "react-icons/fa"; import { FiCommand, FiDelete } from "react-icons/fi"; import { IoMdReturnLeft } from "react-icons/io"; import { PiTreeStructureFill } from "react-icons/pi"; +import { useShallow } from "zustand/react/shallow"; import { NodeDef } from "../behavior3/src/behavior3"; import { FileTreeType, useWorkspace } from "../contexts/workspace-context"; import { getNodeType } from "../misc/b3type"; @@ -273,17 +274,19 @@ const createFolderContextMenu = (copiedPath: string) => { }; export const Explorer: FC = () => { - const workspace = { - close: useWorkspace((state) => state.close), - editing: useWorkspace((state) => state.editing), - editingNodeDef: useWorkspace((state) => state.editingNodeDef), - editors: useWorkspace((state) => state.editors), - fileTree: useWorkspace((state) => state.fileTree), - nodeDefs: useWorkspace((state) => state.nodeDefs), - workdir: useWorkspace((state) => state.workdir), - onEditingNodeDef: useWorkspace((state) => state.onEditingNodeDef), - open: useWorkspace((state) => state.open), - }; + const workspace = useWorkspace( + useShallow((state) => ({ + close: state.close, + editing: state.editing, + editingNodeDef: state.editingNodeDef, + editors: state.editors, + fileTree: state.fileTree, + nodeDefs: state.nodeDefs, + workdir: state.workdir, + onEditingNodeDef: state.onEditingNodeDef, + open: state.open, + })) + ); const { t } = useTranslation(); const [selectedKeys, setSelectedKeys] = useState([]); const [expandedKeys, setExpandedKeys] = useState( diff --git a/src/components/inspector.tsx b/src/components/inspector.tsx index 5882c5f..862b192 100644 --- a/src/components/inspector.tsx +++ b/src/components/inspector.tsx @@ -16,6 +16,7 @@ import { FC, useEffect, useMemo } from "react"; import { useTranslation } from "react-i18next"; import Markdown from "react-markdown"; import { useDebounceCallback } from "usehooks-ts"; +import { useShallow } from "zustand/react/shallow"; import { EditNode, EditTree, useWorkspace } from "../contexts/workspace-context"; import { isBoolType, @@ -44,10 +45,12 @@ interface OptionType extends DefaultOptionType { } const TreeInspector: FC = () => { - const workspace = { - editing: useWorkspace((state) => state.editing), - editingTree: useWorkspace((state) => state.editingTree)!, - }; + const workspace = useWorkspace( + useShallow((state) => ({ + editing: state.editing, + editingTree: state.editingTree!, + })) + ); const { t } = useTranslation(); const [form] = Form.useForm(); @@ -101,15 +104,18 @@ const TreeInspector: FC = () => { }; const NodeInspector: FC = () => { - const workspace = { - editing: useWorkspace((state) => state.editing), - editingNode: useWorkspace((state) => state.editingNode)!, - nodeDefs: useWorkspace((state) => state.nodeDefs), - onEditingNode: useWorkspace((state) => state.onEditingNode), - allFiles: useWorkspace((state) => state.allFiles), - fileTree: useWorkspace((state) => state.fileTree), - relative: useWorkspace((state) => state.relative), - }; + const workspace = useWorkspace( + useShallow((state) => ({ + editing: state.editing, + editingNode: state.editingNode!, + nodeDefs: state.nodeDefs, + allFiles: state.allFiles, + fileTree: state.fileTree, + relative: state.relative, + onEditingNode: state.onEditingNode, + })) + ); + const { t } = useTranslation(); const [form] = Form.useForm(); @@ -920,9 +926,11 @@ const NodeInspector: FC = () => { }; const NodeDefInspector: FC = () => { - const workspace = { - editingNodeDef: useWorkspace((state) => state.editingNodeDef)!, - }; + const workspace = useWorkspace( + useShallow((state) => ({ + editingNodeDef: state.editingNodeDef!, + })) + ); const { t } = useTranslation(); const [form] = Form.useForm(); const def = workspace.editingNodeDef.data; diff --git a/src/components/menu.tsx b/src/components/menu.tsx index 65d5805..66bfe3b 100644 --- a/src/components/menu.tsx +++ b/src/components/menu.tsx @@ -8,6 +8,7 @@ import * as fs from "fs"; import { FC, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { PiTreeStructureFill } from "react-icons/pi"; +import { useShallow } from "zustand/react/shallow"; import { useSetting } from "../contexts/setting-context"; import { useWorkspace } from "../contexts/workspace-context"; import * as b3util from "../misc/b3util"; @@ -40,19 +41,21 @@ ipcRenderer.on("refresh-app-men", () => { export const Menu: FC = () => { const { t } = useTranslation(); const [trigger, setTrigger] = useState(["click"]); - const workspace = { - batchProject: useWorkspace((state) => state.batchProject), - buildProject: useWorkspace((state) => state.buildProject), - createProject: useWorkspace((state) => state.createProject), - editing: useWorkspace((state) => state.editing), - init: useWorkspace((state) => state.init), - open: useWorkspace((state) => state.open), - openProject: useWorkspace((state) => state.openProject), - path: useWorkspace((state) => state.path), - save: useWorkspace((state) => state.save), - saveAll: useWorkspace((state) => state.saveAll), - workdir: useWorkspace((state) => state.workdir), - }; + const workspace = useWorkspace( + useShallow((state) => ({ + batchProject: state.batchProject, + buildProject: state.buildProject, + createProject: state.createProject, + editing: state.editing, + init: state.init, + open: state.open, + openProject: state.openProject, + path: state.path, + save: state.save, + saveAll: state.saveAll, + workdir: state.workdir, + })) + ); const enabled = !!workspace.workdir; const homedir = app.getPath("home"); const settings = { diff --git a/src/components/titlebar.tsx b/src/components/titlebar.tsx index a83e178..86b5568 100644 --- a/src/components/titlebar.tsx +++ b/src/components/titlebar.tsx @@ -1,6 +1,7 @@ import { SearchOutlined } from "@ant-design/icons"; import { Button, Flex, LayoutProps, Select } from "antd"; import React, { FC, useMemo } from "react"; +import { useShallow } from "zustand/react/shallow"; import { NodeDef } from "../behavior3/src/behavior3"; import { useWorkspace } from "../contexts/workspace-context"; import { Hotkey, isMacos } from "../misc/keys"; @@ -15,17 +16,19 @@ interface OptionType { } export const TitleBar: FC = () => { - const workspace = { - allFiles: useWorkspace((state) => state.allFiles), - fileTree: useWorkspace((state) => state.fileTree), - nodeDefs: useWorkspace((state) => state.nodeDefs), - isShowingSearch: useWorkspace((state) => state.isShowingSearch), - onShowingSearch: useWorkspace((state) => state.onShowingSearch), - onEditingNodeDef: useWorkspace((state) => state.onEditingNodeDef), - open: useWorkspace((state) => state.open), - name: useWorkspace((state) => state.path), - relative: useWorkspace((state) => state.relative), - }; + const workspace = useWorkspace( + useShallow((state) => ({ + allFiles: state.allFiles, + fileTree: state.fileTree, + nodeDefs: state.nodeDefs, + isShowingSearch: state.isShowingSearch, + onShowingSearch: state.onShowingSearch, + onEditingNodeDef: state.onEditingNodeDef, + open: state.open, + name: state.path, + relative: state.relative, + })) + ); const searchOptions = useMemo(() => { const options: OptionType[] = []; workspace.allFiles.forEach((file) => { diff --git a/src/components/workspace.tsx b/src/components/workspace.tsx index 7d02ab3..1fa7744 100644 --- a/src/components/workspace.tsx +++ b/src/components/workspace.tsx @@ -8,6 +8,7 @@ import { PiTreeStructureFill } from "react-icons/pi"; import { VscNewFolder, VscRepo } from "react-icons/vsc"; import useForceUpdate from "use-force-update"; import { useWindowSize } from "usehooks-ts"; +import { useShallow } from "zustand/react/shallow"; import { useSetting } from "../contexts/setting-context"; import { EditorStore, useWorkspace } from "../contexts/workspace-context"; import { modal } from "../misc/hooks"; @@ -21,25 +22,24 @@ import { TitleBar } from "./titlebar"; const { Header, Content, Sider } = Layout; export const Workspace: FC = () => { - const workspace = { - buildProject: useWorkspace((state) => state.buildProject), - close: useWorkspace((state) => state.close), - createProject: useWorkspace((state) => state.createProject), - edit: useWorkspace((state) => state.edit), - editing: useWorkspace((state) => state.editing), - editors: useWorkspace((state) => state.editors), - fileTree: useWorkspace((state) => state.fileTree), - find: useWorkspace((state) => state.find), - init: useWorkspace((state) => state.init), - modifiedTime: useWorkspace((state) => state.modifiedTime), - isShowingSearch: useWorkspace((state) => state.isShowingSearch), - onShowingSearch: useWorkspace((state) => state.onShowingSearch), - openProject: useWorkspace((state) => state.openProject), - save: useWorkspace((state) => state.save), - }; - const settings = { - recent: useSetting((state) => state.recent), - }; + const workspace = useWorkspace( + useShallow((state) => ({ + save: state.save, + editors: state.editors, + modifiedTime: state.modifiedTime, + isShowingSearch: state.isShowingSearch, + onShowingSearch: state.onShowingSearch, + openProject: state.openProject, + buildProject: state.buildProject, + close: state.close, + createProject: state.createProject, + edit: state.edit, + editing: state.editing, + fileTree: state.fileTree, + find: state.find, + })) + ); + const settings = useSetting(useShallow((state) => ({ recent: state.recent }))); const [isShowingAlert, setShowingAlert] = useState(false); const { t } = useTranslation(); const forceUpdate = useForceUpdate();