如何制作产品网站模板下载,国内wordpress主题商,织梦cms做多语言的网站,怎样申请自己的网站文章目录 一、项目起航#xff1a;项目初始化与配置二、React 与 Hook 应用#xff1a;实现项目列表三、TS 应用#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook… 文章目录 一、项目起航项目初始化与配置二、React 与 Hook 应用实现项目列表三、TS 应用JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook路由与 URL 状态管理八、用户选择器与项目编辑功能九、深入React 状态管理与Redux机制12345~89.配置redux-toolkit10.应用 redux-toolkit 管理模态框 学习内容来源React React Hook TS 最佳实践-慕课网 相对原教程我在学习开始时2023.03采用的是当前最新版本
项版本react react-dom^18.2.0react-router react-router-dom^6.11.2antd^4.24.8commitlint/cli commitlint/config-conventional^17.4.4eslint-config-prettier^8.6.0husky^8.0.3lint-staged^13.1.2prettier2.8.4json-server0.17.2craco-less^2.0.0craco/craco^7.1.0qs^6.11.0dayjs^1.11.7react-helmet^6.1.0types/react-helmet^6.1.6react-query^6.1.0welldone-software/why-did-you-render^7.0.1emotion/react emotion/styled^11.10.6
具体配置、操作和内容会有差异“坑”也会有所不同。。。 一、项目起航项目初始化与配置 一、项目起航项目初始化与配置 二、React 与 Hook 应用实现项目列表 二、React 与 Hook 应用实现项目列表 三、TS 应用JS神助攻 - 强类型 三、 TS 应用JS神助攻 - 强类型 四、JWT、用户认证与异步请求 四、 JWT、用户认证与异步请求(上) 四、 JWT、用户认证与异步请求(下) 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(下) 六、用户体验优化 - 加载中和错误状态处理 六、用户体验优化 - 加载中和错误状态处理(上) 六、用户体验优化 - 加载中和错误状态处理(中) 六、用户体验优化 - 加载中和错误状态处理(下) 七、Hook路由与 URL 状态管理 七、Hook路由与 URL 状态管理(上) 七、Hook路由与 URL 状态管理(中) 七、Hook路由与 URL 状态管理(下) 八、用户选择器与项目编辑功能 八、用户选择器与项目编辑功能(上) 八、用户选择器与项目编辑功能(下) 九、深入React 状态管理与Redux机制
12 九、深入React 状态管理与Redux机制(一) 34 九、深入React 状态管理与Redux机制(二) 5~8 九、深入React 状态管理与Redux机制(三) 9.配置redux-toolkit Redux Toolkit redux-toolkit 是对 redux 的二次封装主要解决三大痛点
配置复杂需要增加的包太多需要太多模板代码
由于项目最终不会使用到 redux因此接下来新开一个分支用作学习开发创建分支 redux-toolkit
安装依赖
npm i react-redux reduxjs/toolkit # --force新建 src\store\index.tsx
import { configureStore } from reduxjs/toolkitexport const rootReducer {}export const store configureStore({reducer: rootReducer
})export type AppDispatch typeof store.dispatch
export type RootState ReturnTypetypeof store.getState新建 src\screens\ProjectList\projectList.slice.ts
import { createSlice } from reduxjs/toolkit;interface State {projectModalOpen: boolean;
}const initialState: State {projectModalOpen: false
}export const projectListSlice createSlice({name: projectListSlice,initialState,reducers: {openProjectModal(state, action) {},closeProjectModal(state, action) {}}
})问为什么这里可以直接给 state 的属性赋值 答redux 借助内置的 immer 来处理使其变为不可变数据的同时创建“影子状态”最终整体替换原状态 10.应用 redux-toolkit 管理模态框
完善 src\screens\ProjectList\projectList.slice.ts
import { createSlice } from reduxjs/toolkit;
import { RootState } from store;interface State {projectModalOpen: boolean;
}const initialState: State {projectModalOpen: false,
};export const projectListSlice createSlice({name: projectListSlice,initialState,reducers: {openProjectModal(state) {state.projectModalOpen true},closeProjectModal(state) {state.projectModalOpen false},},
});export const projectListActions projectListSlice.actions;export const selectProjectModalOpen (state: RootState) state.projectList.projectModalOpen后续使用方式 引入 import { useDispatch, useSelector } from react-redux;import { projectListActions, selectProjectModalOpen } from ../projectList.slice; 使用 hook 拿到 dispatch const dispatch useDispatch()使用 dispatch 调用打开模态框() dispatch(projectListActions.openProjectModal())使用 dispatch 调用关闭模态框() dispatch(projectListActions.closeProjectModal())使用 hook 获取模态框当前开闭状态useSelector(selectProjectModalOpen) useSelector 用来读根状态树 修改 src\store\index.tsx引入 projectListSlice
import { configureStore } from reduxjs/toolkit;
import { projectListSlice } from screens/ProjectList/projectList.slice;export const rootReducer {projectList: projectListSlice.reducer,
};export const store configureStore({reducer: rootReducer,
});export type AppDispatch typeof store.dispatch;
export type RootState ReturnTypetypeof store.getState;ReturnType 用来读取函数返回值的类型 之前在 AuthenticatedApp子封装模态框组件引入的地方 创建状态量const [isOpen, setIsOpen] useState(false)分别一层一层传入使用到模态框的地方
现在不用啦接下来开始使用 redux 的 dispatch 更改模态框状态
编辑 src\authenticated-app.tsx
...
export const AuthenticatedApp () {
- const [isOpen, setIsOpen] useState(false);...return (Container
- PageHeader
- projectButton{
- ButtonNoPadding typelink onClick{() setIsOpen(true)}
- 创建项目
- /ButtonNoPadding
- }
- /PageHeader/MainRouterRoutesRoutepath/projectselement{
- ProjectList
- projectButton{
- ButtonNoPadding
- typelink
- onClick{() setIsOpen(true)}
-
- 创建项目
- /ButtonNoPadding
- }
- /ProjectList/}/.../Routes/Router/Main
- ProjectModal isOpen{isOpen} onClose{() setIsOpen(false)} /ProjectModal//Container);
};
- const PageHeader (props: { projectButton: JSX.Element }) {const PageHeader () {...return (Header between{true}HeaderLeft gap{true}...
- ProjectPopover {...props} /ProjectPopover/span用户/span/HeaderLeft.../Header);
};
...编辑 src\screens\ProjectList\index.tsx import { useDispatch } from react-redux;import { ButtonNoPadding } from components/lib;import { projectListActions } from ./projectList.slice;- export const ProjectList ({
- projectButton,
- }: {
- projectButton: JSX.Element;
- }) {export const ProjectList () {...const dispatch useDispatch()return (ContainerRow justifyspace-betweenh1项目列表/h1
- {projectButton}ButtonNoPadding typelink onClick{() dispatch(projectListActions.openProjectModal())}创建项目/ButtonNoPadding/Row...List
- projectButton{projectButton}...//Container);
};
...编辑 src\screens\ProjectList\components\List.tsx
...import { useDispatch } from react-redux;import { projectListActions } from ../projectList.slice;interface ListProps extends TablePropsProject {users: User[];refresh?: () void;
- projectButton: JSX.Element;
}// type PropsType OmitListProps, users
export const List ({ users, ...props }: ListProps) {const dispatch useDispatch()...return (Tablepagination{false}columns{[...{render: (text, project) {const items: MenuProps[items] [{key: edit,label: 编辑,onClick: () dispatch(projectListActions.openProjectModal()),},];return (
- Dropdown dropdownRender{() props.projectButton}Dropdown menu{{items}}.../Dropdown);},},]}{...props}/Table);
};编辑 src\screens\ProjectList\components\ProjectModal.tsx
...import { useDispatch, useSelector } from react-redux;import { projectListActions, selectProjectModalOpen } from ../projectList.slice;- export const ProjectModal ({
- isOpen,
- onClose,
- }: {
- isOpen: boolean;
- onClose: () void;
- }) {export const ProjectModal () {const dispatch useDispatch()const projectModalOpen useSelector(selectProjectModalOpen)return (
- Drawer onClose{onClose} open{isOpen} width100%DraweronClose{() dispatch(projectListActions.closeProjectModal())}open{projectModalOpen}width100%h1Project Modal/h1
- Button onClick{onClose}关闭/ButtonButton onClick{() dispatch(projectListActions.closeProjectModal())}关闭/Button/Drawer);
};编辑 src\screens\ProjectList\components\ProjectPopover.tsx
...import { useDispatch } from react-redux;import { projectListActions } from ../projectList.slice;import { ButtonNoPadding } from components/lib;- export const ProjectPopover ({
- projectButton,
- }: {
- projectButton: JSX.Element;
- }) {export const ProjectPopover () {const dispatch useDispatch()...const content (ContentContainerTypography.Text typesecondary收藏项目/Typography.TextList{starProjects?.map((project) (
- List.ItemList.Item key{project.id}List.Item.Meta title{project.name} //List.Item))}/ListDivider /
- {projectButton}ButtonNoPadding typelink onClick{() dispatch(projectListActions.openProjectModal())}创建项目/ButtonNoPadding/ContentContainer);...
};
...现在访问页面会发现有报错
could not find react-redux context value; please ensure the component is wrapped in a Provider这是因为没有将 redux 的 store 绑定到全局 context 上
编辑 src\context\index.tsx
...import { store } from store;import { Provider } from react-redux;export const AppProvider ({ children }: { children: ReactNode }) {return (Provider store{store}QueryClientProvider client{new QueryClient()}AuthProvider{children}/AuthProvider/QueryClientProvider/Provider);
};再次访问页面功能 OK 了 部分引用笔记还在草稿阶段敬请期待。。。