feat: add custom hooks for typed useDispatch and useSelector

This commit is contained in:
siujamo
2026-05-07 10:46:06 +08:00
parent 1a16199f2f
commit af58edbafd
8 changed files with 52 additions and 8 deletions
+2 -2
View File
@@ -3,7 +3,7 @@ import { useMemo } from "react"
import dayjs from "dayjs" import dayjs from "dayjs"
import { Dropdown } from "antd" import { Dropdown } from "antd"
import { AuthApi } from "@/api" import { AuthApi } from "@/api"
import { useAppDispatch, useAppSelector } from "@/store" import { useAppDispatch, useAppSelector } from "@/store/hooks"
import { clearCurrentUser } from "@/store/auth-slice" import { clearCurrentUser } from "@/store/auth-slice"
/** /**
@@ -103,4 +103,4 @@ export default function HeroLayout() {
</footer> </footer>
</div> </div>
) )
} }
+1 -1
View File
@@ -3,7 +3,7 @@ import { Link } from "react-router-dom"
import { FirearmApi } from "@/api" import { FirearmApi } from "@/api"
import FirearmCreateModal from "@/components/firearm-create-modal" import FirearmCreateModal from "@/components/firearm-create-modal"
import FirearmEditModal from "@/components/firearm-edit-modal" import FirearmEditModal from "@/components/firearm-edit-modal"
import { useAppSelector } from "@/store" import { useAppSelector } from "@/store/hooks"
import { Firearm, FirearmType } from "@/types" import { Firearm, FirearmType } from "@/types"
import { Button, Card, Col, Pagination, Popconfirm, Row, Select, Tag, Typography, App } from "antd" import { Button, Card, Col, Pagination, Popconfirm, Row, Select, Tag, Typography, App } from "antd"
+1 -1
View File
@@ -2,7 +2,7 @@ import { useState } from "react"
import { useNavigate } from "react-router-dom" import { useNavigate } from "react-router-dom"
import { App, Button, Card, Form, Input, Typography } from "antd" import { App, Button, Card, Form, Input, Typography } from "antd"
import { AuthApi } from "@/api" import { AuthApi } from "@/api"
import { useAppDispatch } from "@/store" import { useAppDispatch } from "@/store/hooks"
import { setCurrentUser } from "@/store/auth-slice" import { setCurrentUser } from "@/store/auth-slice"
import { LoginRequest } from "@/types" import { LoginRequest } from "@/types"
+1 -1
View File
@@ -16,7 +16,7 @@ import { Link, useSearchParams } from "react-router-dom"
import { ModificationApi, TagApi } from "@/api" import { ModificationApi, TagApi } from "@/api"
import ModificationCreateModal from "@/components/modification-create-modal" import ModificationCreateModal from "@/components/modification-create-modal"
import ModificationEditModal from "@/components/modification-edit-modal" import ModificationEditModal from "@/components/modification-edit-modal"
import { useAppSelector } from "@/store" import { useAppSelector } from "@/store/hooks"
import { Modification } from "@/types" import { Modification } from "@/types"
const pageSize = 10 const pageSize = 10
+5
View File
@@ -13,6 +13,8 @@ function lazy<T extends { default: ComponentType<unknown> }>(importer: () => Pro
} }
} }
const hydrateFallbackElement = <div className="px-4 py-6 text-gray-500">...</div>
/** /**
* Main application router configuration using React Router v6. * Main application router configuration using React Router v6.
* Defines all routes and their corresponding components. * Defines all routes and their corresponding components.
@@ -22,11 +24,13 @@ const router = createBrowserRouter(
{ {
path: "/", path: "/",
element: <HeroLayout />, element: <HeroLayout />,
hydrateFallbackElement,
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [ children: [
{ {
index: true, index: true,
lazy: lazy(() => import("@/page/firearms")), lazy: lazy(() => import("@/page/firearms")),
}, },
{ {
path: "firearms", path: "firearms",
@@ -40,6 +44,7 @@ const router = createBrowserRouter(
}, },
{ {
element: <EmptyLayout />, element: <EmptyLayout />,
hydrateFallbackElement,
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [ children: [
{ {
+6
View File
@@ -0,0 +1,6 @@
import { useDispatch, useSelector } from "react-redux"
import type { AppDispatch, RootState } from "./index"
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
-3
View File
@@ -1,5 +1,4 @@
import { configureStore, combineReducers } from "@reduxjs/toolkit" import { configureStore, combineReducers } from "@reduxjs/toolkit"
import { useDispatch, useSelector } from "react-redux"
import { import {
persistStore, persistStore,
persistReducer, persistReducer,
@@ -46,5 +45,3 @@ export type RootState = ReturnType<typeof rootReducer>
export type AppDispatch = typeof store.dispatch export type AppDispatch = typeof store.dispatch
export type AppStore = typeof store export type AppStore = typeof store
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
+36
View File
@@ -7,6 +7,42 @@ import tailwindcss from "@tailwindcss/vite"
export default defineConfig({ export default defineConfig({
plugins: [react(), tailwindcss()], plugins: [react(), tailwindcss()],
base: "/", base: "/",
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (!id.includes("node_modules")) {
return
}
if (id.includes("react-router")) {
return "router-vendor"
}
if (id.includes("redux") || id.includes("immer")) {
return "redux-vendor"
}
if (id.includes("/node_modules/@ant-design/")) {
return "ant-design-vendor"
}
if (id.includes("/node_modules/rc-")) {
return "antd-rc-vendor"
}
if (
id.includes("/node_modules/react/") ||
id.includes("/node_modules/react-dom/") ||
id.includes("/node_modules/scheduler/")
) {
return "react-vendor"
}
},
},
},
},
resolve: { resolve: {
alias: { alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)), "@": fileURLToPath(new URL("./src", import.meta.url)),