From 93c30e1a63fda606d8d2e0e73ab17fb6d76499df Mon Sep 17 00:00:00 2001 From: caorushizi <84996057@qq.com> Date: Thu, 2 Jan 2025 06:54:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20=20remove=20redux/toolkit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer/package.json | 2 - packages/renderer/src/App.tsx | 17 ++-- packages/renderer/src/layout/App.tsx | 8 +- packages/renderer/src/layout/AppSideBar.tsx | 20 ++-- packages/renderer/src/main.tsx | 6 +- .../HomePage/components/DownloadItem.tsx | 6 +- .../renderer/src/pages/HomePage/index.tsx | 5 +- .../renderer/src/pages/SettingPage/index.tsx | 15 +-- .../SourceExtract/components/BrowserView.tsx | 45 +++++---- .../SourceExtract/components/FavoriteList.tsx | 35 +++---- .../SourceExtract/components/ToolBar.tsx | 65 +++++++------ .../src/pages/SourceExtract/index.tsx | 42 ++++----- packages/renderer/src/store/app.ts | 55 +++++++++++ packages/renderer/src/store/appSlice.ts | 45 --------- packages/renderer/src/store/browser.ts | 93 +++++++++++++++++++ packages/renderer/src/store/browserSlice.ts | 74 --------------- packages/renderer/src/store/download.ts | 39 ++++++++ packages/renderer/src/store/downloadSlice.ts | 29 ------ packages/renderer/src/store/index.ts | 21 ----- packages/renderer/src/utils/index.ts | 4 + pnpm-lock.yaml | 72 -------------- 21 files changed, 326 insertions(+), 372 deletions(-) create mode 100644 packages/renderer/src/store/app.ts delete mode 100644 packages/renderer/src/store/appSlice.ts create mode 100644 packages/renderer/src/store/browser.ts delete mode 100644 packages/renderer/src/store/browserSlice.ts create mode 100644 packages/renderer/src/store/download.ts delete mode 100644 packages/renderer/src/store/downloadSlice.ts delete mode 100644 packages/renderer/src/store/index.ts diff --git a/packages/renderer/package.json b/packages/renderer/package.json index ec0ff1e0..f68e9306 100644 --- a/packages/renderer/package.json +++ b/packages/renderer/package.json @@ -19,7 +19,6 @@ "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-slot": "^1.1.0", - "@reduxjs/toolkit": "^2.2.5", "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "ahooks": "^3.8.0", @@ -39,7 +38,6 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^14.1.2", - "react-redux": "^9.1.2", "react-router-dom": "^6.23.1", "socket.io-client": "^4.8.0", "sort-by": "^1.2.0", diff --git a/packages/renderer/src/App.tsx b/packages/renderer/src/App.tsx index c86d72fd..b96b4b4d 100644 --- a/packages/renderer/src/App.tsx +++ b/packages/renderer/src/App.tsx @@ -1,8 +1,6 @@ import { ConfigProvider, theme } from "antd"; import React, { FC, Suspense, lazy, useEffect } from "react"; -import { useDispatch } from "react-redux"; import { BrowserRouter, Route, Routes } from "react-router-dom"; -import { setAppStore, increase, setBrowserStore, PageMode } from "./store"; import "dayjs/locale/zh-cn"; import zhCN from "antd/locale/zh_CN"; import useElectron from "./hooks/electron"; @@ -14,6 +12,9 @@ import { ThemeContext } from "./context/ThemeContext"; import { SessionStore, useSessionStore } from "./store/session"; import { useShallow } from "zustand/react/shallow"; import { DOWNLOAD_FAIL, DOWNLOAD_SUCCESS, PAGE_LOAD } from "./const"; +import { useAppStore, setAppStoreSelector } from "./store/app"; +import { PageMode, setBrowserSelector, useBrowserStore } from "./store/browser"; +import { downloadStoreSelector, useDownloadStore } from "./store/download"; const AppLayout = lazy(() => import("./layout/App")); const HomePage = lazy(() => import("./pages/HomePage")); @@ -32,12 +33,14 @@ const sessionSelector = (s: SessionStore) => ({ }); const App: FC = () => { - const dispatch = useDispatch(); const [appTheme, setAppTheme] = React.useState<"dark" | "light">("light"); const { addIpcListener, removeIpcListener, getMachineId } = useElectron(); const { setUpdateAvailable, setUploadChecking } = useSessionStore( useShallow(sessionSelector), ); + const { setAppStore } = useAppStore(useShallow(setAppStoreSelector)); + const { setBrowserStore } = useBrowserStore(useShallow(setBrowserSelector)); + const { increase } = useDownloadStore(useShallow(downloadStoreSelector)); const themeChange = (event: MediaQueryListEvent) => { if (event.matches) { @@ -49,17 +52,19 @@ const App: FC = () => { // 监听store变化 const onAppStoreChange = (event: any, store: AppStore) => { - dispatch(setAppStore(store)); + setAppStore(store); }; const onReceiveDownloadItem = () => { - dispatch(increase()); + increase(); }; const onChangePrivacy = () => { - dispatch(setBrowserStore({ url: "", title: "", mode: PageMode.Default })); + setBrowserStore({ url: "", title: "", mode: PageMode.Default }); }; + console.log("App.tsx: onAppStoreChange", onAppStoreChange); + useEffect(() => { const updateAvailable = () => { setUpdateAvailable(true); diff --git a/packages/renderer/src/layout/App.tsx b/packages/renderer/src/layout/App.tsx index 699d7af5..636f0f0f 100644 --- a/packages/renderer/src/layout/App.tsx +++ b/packages/renderer/src/layout/App.tsx @@ -1,22 +1,22 @@ import React, { FC, useEffect } from "react"; import { Outlet, useLocation } from "react-router-dom"; import useElectron from "../hooks/electron"; -import { useDispatch } from "react-redux"; -import { setAppStore } from "../store"; import { useAsyncEffect } from "ahooks"; import { AppHeader } from "./AppHeader"; import { AppSideBar } from "./AppSideBar"; import { tdApp } from "@/utils"; import { CHANGE_PAGE } from "@/const"; +import { useAppStore, setAppStoreSelector } from "@/store/app"; +import { useShallow } from "zustand/react/shallow"; const App: FC = () => { const { getAppStore: ipcGetAppStore } = useElectron(); - const dispatch = useDispatch(); const location = useLocation(); + const { setAppStore } = useAppStore(useShallow(setAppStoreSelector)); useAsyncEffect(async () => { const store = await ipcGetAppStore(); - dispatch(setAppStore(store)); + setAppStore(store); }, []); useEffect(() => { diff --git a/packages/renderer/src/layout/AppSideBar.tsx b/packages/renderer/src/layout/AppSideBar.tsx index c9cc30e4..d6007593 100644 --- a/packages/renderer/src/layout/AppSideBar.tsx +++ b/packages/renderer/src/layout/AppSideBar.tsx @@ -2,8 +2,6 @@ import React, { cloneElement, PropsWithChildren, ReactElement } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { Badge } from "antd"; import useElectron from "../hooks/electron"; -import { useDispatch, useSelector } from "react-redux"; -import { selectAppStore, setAppStore, clearCount, selectCount } from "../store"; import { useTranslation } from "react-i18next"; import { cn, isWeb } from "@/utils"; import { @@ -17,6 +15,12 @@ import { import siderBg from "@/assets/images/sider-bg.png"; import { SessionStore, useSessionStore } from "@/store/session"; import { useShallow } from "zustand/react/shallow"; +import { + useAppStore, + appStoreSelector, + setAppStoreSelector, +} from "@/store/app"; +import { downloadStoreSelector, useDownloadStore } from "@/store/download"; function processLocation(pathname: string) { let name = pathname; @@ -83,9 +87,11 @@ export function AppSideBar({ className }: Props) { const { t } = useTranslation(); const location = useLocation(); const navigate = useNavigate(); - const dispatch = useDispatch(); - const count = useSelector(selectCount); - const appStore = useSelector(selectAppStore); + const { count, clearCount } = useDownloadStore( + useShallow(downloadStoreSelector), + ); + const appStore = useAppStore(useShallow(appStoreSelector)); + const { setAppStore } = useAppStore(useShallow(setAppStoreSelector)); const { updateAvailable } = useSessionStore(useShallow(sessionSelector)); const activeKey = processLocation(location.pathname); @@ -94,7 +100,7 @@ export function AppSideBar({ className }: Props) { e.stopPropagation(); e.preventDefault(); - dispatch(setAppStore({ openInNewWindow: true })); + setAppStore({ openInNewWindow: true }); if (location.pathname === "/source") { navigate("/"); } @@ -109,7 +115,7 @@ export function AppSideBar({ className }: Props) { { - dispatch(clearCount()); + clearCount(); }} activeKey={activeKey} icon={} diff --git a/packages/renderer/src/main.tsx b/packages/renderer/src/main.tsx index af637e96..e121819c 100644 --- a/packages/renderer/src/main.tsx +++ b/packages/renderer/src/main.tsx @@ -1,8 +1,6 @@ import "antd/dist/reset.css"; import React, { StrictMode } from "react"; import { createRoot } from "react-dom/client"; -import { Provider } from "react-redux"; -import store from "./store"; import dayjs from "dayjs"; import "dayjs/locale/zh-cn"; import { tdApp } from "./utils"; @@ -15,8 +13,6 @@ tdApp.init(); createRoot(document.getElementById("root") as HTMLElement).render( - - - + , ); diff --git a/packages/renderer/src/pages/HomePage/components/DownloadItem.tsx b/packages/renderer/src/pages/HomePage/components/DownloadItem.tsx index 9e101ca0..075912d5 100644 --- a/packages/renderer/src/pages/HomePage/components/DownloadItem.tsx +++ b/packages/renderer/src/pages/HomePage/components/DownloadItem.tsx @@ -5,8 +5,6 @@ import { DownloadStatus } from "@/types"; import { Progress } from "antd"; import { PauseCircleOutlined, PlayCircleOutlined } from "@ant-design/icons"; import { useTranslation } from "react-i18next"; -import { useSelector } from "react-redux"; -import { selectAppStore } from "@/store"; import selectedBg from "@/assets/images/select-item-bg.png"; import { DownloadIcon, @@ -28,6 +26,8 @@ import { STOP_DOWNLOAD, } from "@/const"; import { TerminalDrawer } from "./TerminalDrawer"; +import { useAppStore, appStoreSelector } from "@/store/app"; +import { useShallow } from "zustand/react/shallow"; interface Props { item: VideoStat; @@ -50,7 +50,7 @@ export function DownloadItem({ onShowEditForm, progress, }: Props) { - const appStore = useSelector(selectAppStore); + const appStore = useAppStore(useShallow(appStoreSelector)); const { t } = useTranslation(); const { openPlayerWindow } = useElectron(); diff --git a/packages/renderer/src/pages/HomePage/index.tsx b/packages/renderer/src/pages/HomePage/index.tsx index 19785272..2cd5f49c 100644 --- a/packages/renderer/src/pages/HomePage/index.tsx +++ b/packages/renderer/src/pages/HomePage/index.tsx @@ -3,8 +3,6 @@ import PageContainer from "../../components/PageContainer"; import { useMemoizedFn, useMount, usePagination } from "ahooks"; import useElectron from "../../hooks/electron"; import { DownloadFilter, DownloadType } from "../../types"; -import { useSelector } from "react-redux"; -import { selectAppStore } from "../../store"; import { useTranslation } from "react-i18next"; import { DownloadList } from "./components"; import DownloadForm, { @@ -21,6 +19,7 @@ import { useShallow } from "zustand/react/shallow"; import { isDownloadType, isWeb, randomName, tdApp } from "@/utils"; import { CLICK_DOWNLOAD } from "@/const"; import { useLocation } from "react-router-dom"; +import { useAppStore, appStoreSelector } from "@/store/app"; interface Props { filter?: DownloadFilter; @@ -42,7 +41,7 @@ const HomePage: FC = ({ filter = DownloadFilter.list }) => { downloadNow, getLocalIP, } = useElectron(); - const appStore = useSelector(selectAppStore); + const appStore = useAppStore(useShallow(appStoreSelector)); const { t } = useTranslation(); const [localIP, setLocalIP] = useState(""); const newFormRef = useRef(null); diff --git a/packages/renderer/src/pages/SettingPage/index.tsx b/packages/renderer/src/pages/SettingPage/index.tsx index 096a3b72..c94d7915 100644 --- a/packages/renderer/src/pages/SettingPage/index.tsx +++ b/packages/renderer/src/pages/SettingPage/index.tsx @@ -23,8 +23,11 @@ import { FolderOpenOutlined, UploadOutlined, } from "@ant-design/icons"; -import { selectAppStore, setAppStore } from "../../store"; -import { useDispatch, useSelector } from "react-redux"; +import { + useAppStore, + appStoreSelector, + setAppStoreSelector, +} from "@/store/app"; import useElectron from "../../hooks/electron"; import { useMemoizedFn, useRequest } from "ahooks"; import { AppLanguage, AppTheme } from "../../types"; @@ -75,10 +78,10 @@ const SettingPage: React.FC = () => { removeIpcListener, installUpdate, } = useElectron(); - const dispatch = useDispatch(); const { t } = useTranslation(); const formRef = useRef>(); - const settings = useSelector(selectAppStore); + const settings = useAppStore(useShallow(appStoreSelector)); + const { setAppStore } = useAppStore(useShallow(setAppStoreSelector)); const { data: envPath } = useRequest(getEnvPath); const [messageApi, contextHolder] = message.useMessage(); const { updateAvailable, updateChecking } = useSessionStore( @@ -95,7 +98,7 @@ const SettingPage: React.FC = () => { const onSelectDir = async () => { const local = await onSelectDownloadDir(); if (local) { - dispatch(setAppStore({ local })); + setAppStore({ local }); formRef.current?.setFieldValue("local", local); } }; @@ -119,7 +122,7 @@ const SettingPage: React.FC = () => { await ipcSetAppStore(key, values[key]); } } - dispatch(setAppStore(values)); + setAppStore(values); } catch (e: any) { messageApi.error(e.message); } diff --git a/packages/renderer/src/pages/SourceExtract/components/BrowserView.tsx b/packages/renderer/src/pages/SourceExtract/components/BrowserView.tsx index 74db53a6..a98d7375 100644 --- a/packages/renderer/src/pages/SourceExtract/components/BrowserView.tsx +++ b/packages/renderer/src/pages/SourceExtract/components/BrowserView.tsx @@ -5,19 +5,18 @@ import { Button } from "@/components/ui/button"; import WebView from "@/components/WebView"; import useElectron from "@/hooks/electron"; import { - addSource, BrowserStatus, - deleteSource, + browserStoreSelector, PageMode, - selectBrowserStore, - setBrowserStore, -} from "@/store"; + setBrowserSelector, + useBrowserStore, +} from "@/store/browser"; import { generateUrl, randomName } from "@/utils"; import { useMemoizedFn } from "ahooks"; import { Empty, Space, Spin, message, Splitter } from "antd"; import React, { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useDispatch, useSelector } from "react-redux"; +import { useShallow } from "zustand/react/shallow"; export function BrowserView() { const { @@ -30,10 +29,12 @@ export function BrowserView() { showDownloadDialog: ipcShowDownloadDialog, } = useElectron(); const downloadForm = useRef(null); - const store = useSelector(selectBrowserStore); + const store = useBrowserStore(useShallow(browserStoreSelector)); + const { addSource, setBrowserStore, deleteSource } = useBrowserStore( + useShallow(setBrowserSelector), + ); const { t } = useTranslation(); const [placeHolder, setPlaceHolder] = useState(""); - const dispatch = useDispatch(); const [messageApi, contextHolder] = message.useMessage(); useEffect(() => { @@ -57,7 +58,7 @@ export function BrowserView() { }; const onWebviewLinkMessage = async (e: unknown, data: any) => { - dispatch(addSource(data)); + addSource(data); }; addIpcListener("show-download-dialog", onShowDownloadDialog); @@ -71,13 +72,11 @@ export function BrowserView() { const onClickGoHome = async () => { await webviewGoHome(); - dispatch( - setBrowserStore({ - url: "", - title: "", - mode: PageMode.Default, - }), - ); + setBrowserStore({ + url: "", + title: "", + mode: PageMode.Default, + }); }; const confirmDownload = async (now?: boolean) => { @@ -106,13 +105,11 @@ export function BrowserView() { }; const loadUrl = (url: string) => { - dispatch( - setBrowserStore({ - url, - mode: PageMode.Browser, - status: BrowserStatus.Loading, - }), - ); + setBrowserStore({ + url, + mode: PageMode.Browser, + status: BrowserStatus.Loading, + }); webviewLoadURL(url); }; @@ -196,7 +193,7 @@ export function BrowserView() { } onClick={() => { - dispatch(deleteSource(item.url)); + deleteSource(item.url); }} /> diff --git a/packages/renderer/src/pages/SourceExtract/components/FavoriteList.tsx b/packages/renderer/src/pages/SourceExtract/components/FavoriteList.tsx index 59f5b81b..403b33c0 100644 --- a/packages/renderer/src/pages/SourceExtract/components/FavoriteList.tsx +++ b/packages/renderer/src/pages/SourceExtract/components/FavoriteList.tsx @@ -1,14 +1,19 @@ import useElectron from "@/hooks/electron"; -import { BrowserStatus, PageMode, setBrowserStore } from "@/store"; import { getFavIcon, tdApp } from "@/utils"; import { PlusOutlined } from "@ant-design/icons"; import { useRequest } from "ahooks"; import { Form, Input, message, Modal } from "antd"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useDispatch } from "react-redux"; import { FavItem } from "./FavItem"; import { ADD_FAVORITE, OPEN_FAVORITE } from "@/const"; +import { + BrowserStatus, + PageMode, + setBrowserSelector, + useBrowserStore, +} from "@/store/browser"; +import { useShallow } from "zustand/react/shallow"; export function FavoriteList() { const { @@ -24,17 +29,15 @@ export function FavoriteList() { const { t } = useTranslation(); const [messageApi, contextHolder] = message.useMessage(); const [favoriteAddForm] = Form.useForm(); - const dispatch = useDispatch(); const [isModalOpen, setIsModalOpen] = useState(false); + const { setBrowserStore } = useBrowserStore(useShallow(setBrowserSelector)); const loadUrl = (url: string) => { - dispatch( - setBrowserStore({ - url, - mode: PageMode.Browser, - status: BrowserStatus.Loading, - }), - ); + setBrowserStore({ + url, + mode: PageMode.Browser, + status: BrowserStatus.Loading, + }); webviewLoadURL(url); }; @@ -77,13 +80,11 @@ export function FavoriteList() { useEffect(() => { const onClickLoadItem = (item: Favorite) => { - dispatch( - setBrowserStore({ - url: item.url, - mode: PageMode.Browser, - status: BrowserStatus.Loading, - }), - ); + setBrowserStore({ + url: item.url, + mode: PageMode.Browser, + status: BrowserStatus.Loading, + }); webviewLoadURL(item.url); }; diff --git a/packages/renderer/src/pages/SourceExtract/components/ToolBar.tsx b/packages/renderer/src/pages/SourceExtract/components/ToolBar.tsx index 6810f346..7de46450 100644 --- a/packages/renderer/src/pages/SourceExtract/components/ToolBar.tsx +++ b/packages/renderer/src/pages/SourceExtract/components/ToolBar.tsx @@ -1,18 +1,9 @@ import useElectron from "@/hooks/electron"; -import { - BrowserStatus, - PageMode, - selectAppStore, - selectBrowserStore, - setAppStore, - setBrowserStore, -} from "@/store"; import { cn, generateUrl, getFavIcon, tdApp } from "@/utils"; import { useRequest } from "ahooks"; import { Input, Tooltip } from "antd"; import React, { useContext, useMemo } from "react"; import { useTranslation } from "react-i18next"; -import { useDispatch, useSelector } from "react-redux"; import { BackIcon, HomeIcon, @@ -29,6 +20,19 @@ import { IconButton } from "@/components/IconButton"; import { ThemeContext } from "@/context/ThemeContext"; import { EyeInvisibleOutlined } from "@ant-design/icons"; import { OPEN_URL } from "@/const"; +import { + useAppStore, + appStoreSelector, + setAppStoreSelector, +} from "@/store/app"; +import { useShallow } from "zustand/react/shallow"; +import { + BrowserStatus, + browserStoreSelector, + PageMode, + setBrowserSelector, + useBrowserStore, +} from "@/store/browser"; interface Props { page: boolean; @@ -47,10 +51,11 @@ export function ToolBar({ page }: Props) { webviewUrlContextMenu, } = useElectron(); const theme = useContext(ThemeContext); - const store = useSelector(selectBrowserStore); - const appStore = useSelector(selectAppStore); + const store = useBrowserStore(useShallow(browserStoreSelector)); + const { setBrowserStore } = useBrowserStore(useShallow(setBrowserSelector)); + const appStore = useAppStore(useShallow(appStoreSelector)); + const { setAppStore } = useAppStore(useShallow(setAppStoreSelector)); const { t } = useTranslation(); - const dispatch = useDispatch(); const { data: favoriteList = [], refresh } = useRequest(getFavorites); const disabled = @@ -60,11 +65,9 @@ export function ToolBar({ page }: Props) { const onSetDefaultUA = () => { const nextMode = !appStore.isMobile; setUserAgent(nextMode); - dispatch( - setAppStore({ - isMobile: nextMode, - }), - ); + setAppStore({ + isMobile: nextMode, + }); }; const curIsFavorite = useMemo(() => { @@ -87,30 +90,26 @@ export function ToolBar({ page }: Props) { if (!back) { // TODO: Reset title // document.title = originTitle.current; - dispatch(setBrowserStore({ url: "", title: "", mode: PageMode.Default })); + setBrowserStore({ url: "", title: "", mode: PageMode.Default }); } }; const onClickGoHome = async () => { await webviewGoHome(); - dispatch( - setBrowserStore({ - url: "", - title: "", - mode: PageMode.Default, - }), - ); + setBrowserStore({ + url: "", + title: "", + mode: PageMode.Default, + }); }; const loadUrl = (url: string) => { tdApp.onEvent(OPEN_URL); - dispatch( - setBrowserStore({ - url, - mode: PageMode.Browser, - status: BrowserStatus.Loading, - }), - ); + setBrowserStore({ + url, + mode: PageMode.Browser, + status: BrowserStatus.Loading, + }); webviewLoadURL(url); }; @@ -219,7 +218,7 @@ export function ToolBar({ page }: Props) { value={store.url} onChange={(e) => { const url = e.target.value; - dispatch(setBrowserStore({ url })); + setBrowserStore({ url }); }} onFocus={(e) => { e.target.select(); diff --git a/packages/renderer/src/pages/SourceExtract/index.tsx b/packages/renderer/src/pages/SourceExtract/index.tsx index ba24220c..0bb9a343 100644 --- a/packages/renderer/src/pages/SourceExtract/index.tsx +++ b/packages/renderer/src/pages/SourceExtract/index.tsx @@ -1,19 +1,20 @@ import { useAsyncEffect } from "ahooks"; import React, { useEffect, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; import PageContainer from "../../components/PageContainer"; import useElectron from "../../hooks/electron"; -import { - BrowserStatus, - PageMode, - selectBrowserStore, - setAppStore, - setBrowserStore, -} from "../../store"; import { FavoriteList } from "./components/FavoriteList"; import { BrowserView } from "./components/BrowserView"; import { ToolBar } from "./components/ToolBar"; import { cn } from "@/utils"; +import { useAppStore, setAppStoreSelector } from "@/store/app"; +import { useShallow } from "zustand/react/shallow"; +import { + BrowserStatus, + browserStoreSelector, + PageMode, + setBrowserSelector, + useBrowserStore, +} from "@/store/browser"; interface SourceExtractProps { page?: boolean; @@ -26,18 +27,19 @@ const SourceExtract: React.FC = ({ page = false }) => { getSharedState, getAppStore: ipcGetAppStore, } = useElectron(); - const dispatch = useDispatch(); - const store = useSelector(selectBrowserStore); + const { setAppStore } = useAppStore(useShallow(setAppStoreSelector)); + const store = useBrowserStore(useShallow(browserStoreSelector)); + const { setBrowserStore } = useBrowserStore(useShallow(setBrowserSelector)); const originTitle = useRef(document.title); useAsyncEffect(async () => { const store = await ipcGetAppStore(); - dispatch(setAppStore(store)); + setAppStore(store); }, []); useAsyncEffect(async () => { const state = await getSharedState(); - dispatch(setBrowserStore(state)); + setBrowserStore(state); }, []); useEffect(() => { @@ -56,7 +58,7 @@ const SourceExtract: React.FC = ({ page = false }) => { const setPageInfo = ({ url, title }: UrlDetail) => { document.title = title; - dispatch(setBrowserStore({ url, title })); + setBrowserStore({ url, title }); }; const onDomReady = (e: unknown, info: UrlDetail) => { @@ -64,18 +66,16 @@ const SourceExtract: React.FC = ({ page = false }) => { }; const onFailLoad = (e: unknown, data: { code: number; desc: string }) => { - dispatch( - setBrowserStore({ - status: BrowserStatus.Failed, - errCode: data.code, - errMsg: data.desc, - }), - ); + setBrowserStore({ + status: BrowserStatus.Failed, + errCode: data.code, + errMsg: data.desc, + }); }; const onDidNavigate = (e: unknown, info: UrlDetail) => { setPageInfo(info); - dispatch(setBrowserStore({ status: BrowserStatus.Loaded })); + setBrowserStore({ status: BrowserStatus.Loaded }); }; const onDidNavigateInPage = (e: unknown, info: UrlDetail) => { diff --git a/packages/renderer/src/store/app.ts b/packages/renderer/src/store/app.ts new file mode 100644 index 00000000..1022808d --- /dev/null +++ b/packages/renderer/src/store/app.ts @@ -0,0 +1,55 @@ +import { AppLanguage, AppTheme } from "../types"; +import i18n from "../i18n"; +import { create } from "zustand"; +import { immer } from "zustand/middleware/immer"; + +const initialState: AppStore = { + local: "", + promptTone: true, + proxy: "", + useProxy: false, + deleteSegments: true, + openInNewWindow: false, + theme: AppTheme.System, + useExtension: false, + isMobile: false, + maxRunner: 2, + language: AppLanguage.System, + showTerminal: false, + privacy: false, + machineId: "", + downloadProxySwitch: false, + autoUpgrade: true, + audioMuted: true, +}; + +type Actions = { + setAppStore: (values: Partial) => void; +}; + +export const useAppStore = create()( + immer((set) => ({ + ...initialState, + setAppStore: (values) => + set((state) => { + const { language } = values; + if (language) { + i18n.changeLanguage(language); + } + + Object.entries(values).forEach(([key, val]) => { + (state as any)[key] = val; + }); + }), + })), +); + +export const appStoreSelector = (state: AppStore & Actions) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { setAppStore, ...appStore } = state; + return appStore; +}; + +export const setAppStoreSelector = (state: AppStore & Actions) => { + return { setAppStore: state.setAppStore }; +}; diff --git a/packages/renderer/src/store/appSlice.ts b/packages/renderer/src/store/appSlice.ts deleted file mode 100644 index f7dd1ed2..00000000 --- a/packages/renderer/src/store/appSlice.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; -import { RootState } from "."; -import { AppLanguage, AppTheme } from "../types"; -import i18n from "../i18n"; - -const initialState: AppStore = { - local: "", - promptTone: true, - proxy: "", - useProxy: false, - deleteSegments: true, - openInNewWindow: false, - theme: AppTheme.System, - useExtension: false, - isMobile: false, - maxRunner: 2, - language: AppLanguage.System, - showTerminal: false, - privacy: false, - machineId: "", - downloadProxySwitch: false, - autoUpgrade: true, - audioMuted: true, -}; - -export const appSlice = createSlice({ - name: "app", - initialState, - reducers: { - setAppStore(state, { payload }: PayloadAction>) { - Object.keys(payload).forEach((key) => { - if (payload[key] != null) { - state[key] = payload[key] as never; - if (key === "language") { - i18n.changeLanguage(payload[key] as string); - } - } - }); - }, - }, -}); - -export const { setAppStore } = appSlice.actions; -export const selectAppStore = (state: RootState) => state.app; -export default appSlice.reducer; diff --git a/packages/renderer/src/store/browser.ts b/packages/renderer/src/store/browser.ts new file mode 100644 index 00000000..0f50acae --- /dev/null +++ b/packages/renderer/src/store/browser.ts @@ -0,0 +1,93 @@ +import useElectron from "../hooks/electron"; +import { DownloadType } from "@/types"; +import { convertPlainObject } from "@/utils"; +import { create } from "zustand"; +import { immer } from "zustand/middleware/immer"; + +const { setSharedState } = useElectron(); + +export enum PageMode { + Default = "default", + Browser = "browser", +} + +export enum BrowserStatus { + Default = "default", + Loaded = "loaded", + Loading = "loading", + Failed = "failed", +} + +export interface SourceData { + id: number; + url: string; + documentURL: string; + name: string; + type: DownloadType; + headers?: string; +} + +const initialState: BrowserStore = { + mode: PageMode.Default, + url: "", + title: "", + status: BrowserStatus.Default, + errMsg: "", + errCode: 0, + sources: [], +}; + +type Actions = { + setBrowserStore: (values: Partial) => void; + addSource: (source: SourceData) => void; + deleteSource: (url: string) => void; + setSources: (sources: SourceData[]) => void; +}; + +export const useBrowserStore = create()( + immer((set) => ({ + ...initialState, + setBrowserStore: (values) => + set((state) => { + Object.keys(values).forEach((key) => { + if (values[key] != null) { + state[key] = values[key] as never; + } + }); + setSharedState(convertPlainObject(state)); + }), + addSource: (source) => + set((state) => { + state.sources.push(source); + }), + deleteSource: (url) => + set((state) => { + state.sources = state.sources.filter((item: any) => item.url !== url); + }), + setSources: (sources) => + set((state) => { + state.sources = sources; + }), + })), +); + +export const browserStoreSelector = (state: BrowserStore & Actions) => { + return { + mode: state.mode, + url: state.url, + title: state.title, + status: state.status, + errMsg: state.errMsg, + errCode: state.errCode, + sources: state.sources, + }; +}; + +export const setBrowserSelector = (state: BrowserStore & Actions) => { + return { + setBrowserStore: state.setBrowserStore, + addSource: state.addSource, + deleteSource: state.deleteSource, + setSources: state.setSources, + }; +}; diff --git a/packages/renderer/src/store/browserSlice.ts b/packages/renderer/src/store/browserSlice.ts deleted file mode 100644 index 29bd1e9c..00000000 --- a/packages/renderer/src/store/browserSlice.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; -import { RootState } from "."; -import useElectron from "../hooks/electron"; -import { DownloadType } from "@/types"; - -const { setSharedState } = useElectron(); - -export enum PageMode { - Default = "default", - Browser = "browser", -} - -export enum BrowserStatus { - Default = "default", - Loaded = "loaded", - Loading = "loading", - Failed = "failed", -} - -export interface SourceData { - id: number; - url: string; - documentURL: string; - name: string; - type: DownloadType; - headers?: string; -} - -const initialState: BrowserStore = { - mode: PageMode.Default, - url: "", - title: "", - status: BrowserStatus.Default, - errMsg: "", - sources: [], -}; - -const convertPlainObject = (obj: unknown) => { - return JSON.parse(JSON.stringify(obj)); -}; - -export const browserSlice = createSlice({ - name: "browser", - initialState, - reducers: { - setBrowserStore(state, action: PayloadAction>) { - const { payload } = action; - Object.keys(payload).forEach((key) => { - if (payload[key] != null) { - state[key] = payload[key] as never; - } - }); - // FIXME: Asynchronous function - setSharedState(convertPlainObject(state)); - }, - setSources(state: BrowserStore, action: PayloadAction) { - state.sources = action.payload; - }, - addSource(state: BrowserStore, action: PayloadAction) { - state.sources.push(action.payload); - }, - deleteSource(state: BrowserStore, action: PayloadAction) { - state.sources = state.sources.filter( - (item) => item.url !== action.payload, - ); - }, - }, -}); - -export const { setBrowserStore, setSources, addSource, deleteSource } = - browserSlice.actions; -export const selectUrl = (state: RootState) => state.browser.url; -export const selectBrowserStore = (state: RootState) => state.browser; -export default browserSlice.reducer; diff --git a/packages/renderer/src/store/download.ts b/packages/renderer/src/store/download.ts new file mode 100644 index 00000000..0ef3d7da --- /dev/null +++ b/packages/renderer/src/store/download.ts @@ -0,0 +1,39 @@ +import { create } from "zustand"; +import { immer } from "zustand/middleware/immer"; + +interface DownloadStore { + downloadList: string[]; + count: number; +} + +const initialState: DownloadStore = { + downloadList: [], + count: 0, +}; + +type Actions = { + clearCount: () => void; + increase: () => void; +}; + +export const useDownloadStore = create()( + immer((set) => ({ + ...initialState, + clearCount: () => + set((state) => { + state.count = 0; + }), + increase: () => + set((state) => { + state.count += 1; + }), + })), +); + +export const downloadStoreSelector = (state: DownloadStore & Actions) => { + return { + count: state.count, + clearCount: state.clearCount, + increase: state.increase, + }; +}; diff --git a/packages/renderer/src/store/downloadSlice.ts b/packages/renderer/src/store/downloadSlice.ts deleted file mode 100644 index 1656f2fc..00000000 --- a/packages/renderer/src/store/downloadSlice.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createSlice } from "@reduxjs/toolkit"; -import { RootState } from "."; - -interface DownloadStore { - downloadList: string[]; - count: number; -} - -const initialState: DownloadStore = { - downloadList: [], - count: 0, -}; - -export const downloadSlice = createSlice({ - name: "download", - initialState, - reducers: { - clearCount(state) { - state.count = 0; - }, - increase(state) { - state.count++; - }, - }, -}); - -export const { clearCount, increase } = downloadSlice.actions; -export const selectCount = (state: RootState) => state.download.count; -export default downloadSlice.reducer; diff --git a/packages/renderer/src/store/index.ts b/packages/renderer/src/store/index.ts deleted file mode 100644 index 0b36f056..00000000 --- a/packages/renderer/src/store/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { configureStore } from "@reduxjs/toolkit"; -import appSlice from "./appSlice"; -import browserSlice from "./browserSlice"; -import downloadSlice from "./downloadSlice"; - -const store = configureStore({ - reducer: { - app: appSlice, - download: downloadSlice, - browser: browserSlice, - }, -}); - -export type RootState = ReturnType; -export type AppDispatch = typeof store.dispatch; - -export * from "./appSlice"; -export * from "./browserSlice"; -export * from "./downloadSlice"; - -export default store; diff --git a/packages/renderer/src/utils/index.ts b/packages/renderer/src/utils/index.ts index e7a47805..2feba579 100644 --- a/packages/renderer/src/utils/index.ts +++ b/packages/renderer/src/utils/index.ts @@ -83,3 +83,7 @@ export const isWeb = import.meta.env.APP_TARGET === "web"; export function isDownloadType(value: string): value is DownloadType { return Object.values(DownloadType).includes(value as DownloadType); } + +export const convertPlainObject = (obj: unknown) => { + return JSON.parse(JSON.stringify(obj)); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bea87285..cefe9c56 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -597,9 +597,6 @@ importers: '@radix-ui/react-slot': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.3)(react@18.3.1) - '@reduxjs/toolkit': - specifier: ^2.2.5 - version: 2.2.5(react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1))(react@18.3.1) '@xterm/addon-fit': specifier: ^0.10.0 version: 0.10.0(@xterm/xterm@5.5.0) @@ -657,9 +654,6 @@ importers: react-i18next: specifier: ^14.1.2 version: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-redux: - specifier: ^9.1.2 - version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1) react-router-dom: specifier: ^6.23.1 version: 6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1960,17 +1954,6 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@reduxjs/toolkit@2.2.5': - resolution: {integrity: sha512-aeFA/s5NCG7NoJe/MhmwREJxRkDs0ZaSqt0MxhWUrwCf1UQXpwR87RROJEql0uAkLI6U7snBOYOcKw83ew3FPg==} - peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 - react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 - peerDependenciesMeta: - react: - optional: true - react-redux: - optional: true - '@remix-run/router@1.16.1': resolution: {integrity: sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==} engines: {node: '>=14.0.0'} @@ -2484,9 +2467,6 @@ packages: '@types/undertaker@1.2.11': resolution: {integrity: sha512-j1Z0V2ByRHr8ZK7eOeGq0LGkkdthNFW0uAZGY22iRkNQNL9/vAV0yFPr1QN3FM/peY5bxs9P+1f0PYJTQVa5iA==} - '@types/use-sync-external-store@0.0.3': - resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} - '@types/verror@1.10.10': resolution: {integrity: sha512-l4MM0Jppn18hb9xmM6wwD1uTdShpf9Pn80aXTStnK1C94gtPvJcV2FrDmbOQUAQfJ1cKZHktkQUDwEqaAKXMMg==} @@ -6213,18 +6193,6 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-redux@9.1.2: - resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==} - peerDependencies: - '@types/react': ^18.2.25 - react: ^18.0 - redux: ^5.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - redux: - optional: true - react-remove-scroll-bar@2.3.6: resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} engines: {node: '>=10'} @@ -6308,17 +6276,9 @@ packages: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} - redux-thunk@3.1.0: - resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} - peerDependencies: - redux: ^5.0.0 - redux@4.2.1: resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} - redux@5.0.1: - resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} - reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -6359,9 +6319,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - reselect@5.1.0: - resolution: {integrity: sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==} - resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} @@ -8758,16 +8715,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@reduxjs/toolkit@2.2.5(react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1))(react@18.3.1)': - dependencies: - immer: 10.1.1 - redux: 5.0.1 - redux-thunk: 3.1.0(redux@5.0.1) - reselect: 5.1.0 - optionalDependencies: - react: 18.3.1 - react-redux: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1) - '@remix-run/router@1.16.1': {} '@remusao/guess-url-type@1.3.0': {} @@ -9210,8 +9157,6 @@ snapshots: '@types/undertaker-registry': 1.0.4 async-done: 1.3.2 - '@types/use-sync-external-store@0.0.3': {} - '@types/verror@1.10.10': optional: true @@ -13654,15 +13599,6 @@ snapshots: react-is@18.3.1: {} - react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1): - dependencies: - '@types/use-sync-external-store': 0.0.3 - react: 18.3.1 - use-sync-external-store: 1.2.2(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.3 - redux: 5.0.1 - react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 @@ -13769,16 +13705,10 @@ snapshots: dependencies: resolve: 1.22.8 - redux-thunk@3.1.0(redux@5.0.1): - dependencies: - redux: 5.0.1 - redux@4.2.1: dependencies: '@babel/runtime': 7.24.5 - redux@5.0.1: {} - reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.6: @@ -13814,8 +13744,6 @@ snapshots: require-from-string@2.0.2: {} - reselect@5.1.0: {} - resize-observer-polyfill@1.5.1: {} resolve-alpn@1.2.1: {}