diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index f0e2998..cf7feab 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -99,6 +99,7 @@ export default { text: 'React', items: [ { text: 'React', link: '/frontEnd/frame/React/' }, + { text: '深入React', link: '/frontEnd/frame/React/Learn' }, { text: 'Fiber', link: '/frontEnd/frame/React/Fiber' } ] }, @@ -108,7 +109,10 @@ export default { }, { text: '其他', - items: [{ text: '表单', link: '/frontEnd/frame/Other/form' }] + items: [ + { text: '表单', link: '/frontEnd/frame/Other/form' }, + { text: '项目搭建', link: '/frontEnd/frame/Other/build' } + ] } ], diff --git a/docs/frontEnd/frame/Other/build.md b/docs/frontEnd/frame/Other/build.md new file mode 100644 index 0000000..b0e7156 --- /dev/null +++ b/docs/frontEnd/frame/Other/build.md @@ -0,0 +1,190 @@ +# 大型项目搭建 + +在大型前端应用的开发中,每个模块都需要细化和规范化,以确保系统的可维护性、可扩展性以及开发效率。以下是对前面提到的各个模块的细化说明: + +## 模块化和组件化开发 + +- 组件结构设计: + + - 组件分为页面组件(Page Components)和可复用组件(Reusable Components)。 + - 页面组件负责布局和业务逻辑,每个页面组件通常对应一个 URL 路径。 + - 可复用组件应保持独立性,具备清晰的输入输出(通过 props 和 events 通信)。 + - 容器组件(Container Components):负责数据获取和逻辑处理,内部调用展示组件(Presentational Components),展示组件只负责渲染。 + +- 目录结构设计: + + - 根据项目规模,按功能模块划分目录,确保组件的可维护性。 + - 一个典型的目录结构: + + ```scss + src/ + ├── components/ // 可复用的基础组件 + ├── pages/ // 页面级别组件 + ├── services/ // 数据获取和 API 封装 + ├── store/ // 全局状态管理 + ├── utils/ // 公共工具函数 + ├── assets/ // 静态资源 + ├── hooks/ // 自定义 Hooks + ├── styles/ // 全局样式 + ``` + +- 代码分割与懒加载: + + - 对于大型应用,保持每个组件独立并进行代码分割非常重要。可以利用动态导入的方式懒加载某些组件: + + ```js + const SomeComponent = React.lazy(() => import('./SomeComponent')) + ``` + +## 状态管理 + +细粒度状态管理: + +- 避免将所有状态都放入全局管理,应该根据应用需求决定哪些状态需要全局共享,哪些只需局部管理。将组件内部状态(如表单输入)与全局状态(如用户信息)分开管理。 + +Redux的最佳实践: + +- 使用Redux Toolkit简化 Redux 的写法。 +- 将状态分为不同的slice(切片),每个切片负责管理一个功能模块的状态: + +```js +const userSlice = createSlice({ + name: 'user', + initialState: { name: '', age: 0 }, + reducers: { + setUser(state, action) { + state.name = action.payload.name + state.age = action.payload.age + } + } +}) +``` + +异步状态管理: + +- 使用Redux Thunk或Redux Saga管理异步逻辑,确保异步操作(如 API 请求)不会阻塞 UI 渲染。 + +React Context API 和 Hooks: + +- 对于简单的状态管理,可以结合Context API与useReducer或useState来管理局部状态,避免过度依赖 Redux 造成复杂性。 + +## 路由管理 + +使用React Router来进行路由搭建。 + +通过配置的形式来进行路由创建: + +```js +export const Routers = [ + { + path: '/', + component: lazy(() => import('../layouts/basicLayout')), + children: [ + // xxx + ] + } + // xxx +] +``` + +在App组件内通过循环渲染来生成组件: + +```jsx + + + {routers.map(route => { + const Element = route.component + return ( + }> + {route.children ? renderRoutes(route.children) : null} + + ) + })} + + +``` + +- 懒加载与按需加载: + + - 每个路由组件都可以通过 React.lazy 进行懒加载,提升初始页面加载速度。 + - 路由表可以动态生成,支持权限控制,根据用户角色动态加载不同的页面模块。 + +- 守卫和权限控制: + + - 使用高阶组件(HOC)或路由守卫实现页面访问控制。基于用户角色或权限配置,动态跳转或限制某些路由访问。 + +## 性能优化 + +- 长列表优化: + + - 使用虚拟滚动技术渲染长列表,避免渲染大量 DOM 元素: + +```jsx +import { FixedSizeList as List } from 'react-window' +// xxx +; + {({ index, style }) =>
Row {index}
} +
+``` + +- 图片优化: + + - 图片应使用懒加载,并按需调整大小(使用 CSS 中的 srcset): + + ```html + image + ``` + + - 使用精灵图 + +- 代码分割: + + - 通过 Webpack/Vite 实现代码的动态加载(code splitting),避免一次性加载整个应用的所有代码。 + +## 构建工具的选择 + +- Webpack/Vite 配置优化: + + - Webpack:通过设置 splitChunks 和 bundle analyzer 进行代码拆分和打包优化。 + - Vite:利用 Vite 的热更新和模块预构建功能,提升开发体验和构建速度。 + +- 生产环境优化: + + - 压缩代码、启用 Tree Shaking 删除无用代码、使用 Brotli 或 Gzip 压缩传输静态资源。 + +## API 管理与数据获取 + +- API 封装与抽象: + + - 将所有 API 请求统一封装成服务模块(service layer),避免在组件中直接调用 fetch 或 axios。 + +- 提供统一的错误处理和请求拦截: + +```js +const axiosInstance = axios.create({ baseURL: '/api' }) +axiosInstance.interceptors.response.use( + response => response, + error => Promise.reject(error) +) +``` + +## CI/CD 集成 + +- 自动化构建与部署: + + - 使用 GitHub Actions 或 Jenkins 配置CI/CD 流水线,自动运行测试和构建,并自动部署到生产环境。 + +- Lint 检查: + + - 在 CI 中集成 ESLint 和 Prettier 检查代码质量,确保代码风格统一。 + +## 团队协作 + +- Git 分支管理: + + - 使用 Git Flow 或 Trunk-based Development 来管理开发过程中的多个分支,确保功能开发、测试和发布流程的规范性。 + +- 代码评审和协作工具: + + - 借助Code Review工具(如 GitHub、GitLab)进行代码评审,确保代码质量。 + - 使用 Jira 或 Trello 来管理任务,确保团队协作有序。 diff --git a/docs/frontEnd/frame/React/Learn.md b/docs/frontEnd/frame/React/Learn.md new file mode 100644 index 0000000..a024544 --- /dev/null +++ b/docs/frontEnd/frame/React/Learn.md @@ -0,0 +1,93 @@ +# 深入理解React + +深入理解 React + +## 组件的本质 + +在 React 中,组件是核心构建单元。组件可以是函数组件或类组件,它们的本质都是 JavaScript 函数或类,接收 props 并返回 UI(通常是 JSX 语法描述的虚拟 DOM)。深入理解组件的渲染和生命周期,可以帮助你优化性能。 + +关键要点: + +- 函数组件 vs 类组件:了解函数组件如何通过 Hooks 管理状态和副作用,并理解类组件的生命周期。 +- 无状态组件和有状态组件:无状态组件更容易优化,尽可能使用函数组件和 Hooks。 +- 受控组件和非受控组件:掌控表单处理时,使用受控组件能更精确地控制表单的状态。 + +首先讲讲这个类组件。在`React`17.x,也就是`hooks`出现之前,只有类组件才有状态state这个`概念`,函数组件就是一个纯函数,纯函数即是`相同的输入得到相同的输出的这一类函数`,因此函数组件无法做到有状态。 + +要做到有状态就需要类组件。类组件被设计如下进行状态管理,state即使这个组件的状态,通过`this.setState`来修改状态,并触发组件重新渲染 + +```jsx +import React, { Component } from 'react' + +class Counter extends Component { + constructor(props) { + super(props) + // 初始化 state + this.state = { + count: 0 + } + } + + // 增加计数的方法 + incrementCount = () => { + // 更新状态 + this.setState({ count: this.state.count + 1 }) + } + + render() { + return ( +
+

Count: {this.state.count}

+ +
+ ) + } +} + +export default Counter +``` + +同时React还在类组件中提供了一套生命周期的钩子,如以下: + +- 挂载阶段(Mounting):组件被创建并插入 DOM。 +- 更新阶段(Updating):组件的状态或 props 发生变化时触发更新。 +- 卸载阶段(Unmounting):组件从 DOM 中移除。 + +这给开发者提供了实现副作用功能的地方,比如:请求数据,销毁内存等。平常基础开发都会使用类组件来进行开发,上面的写法在量上面还是比较的多和麻烦。 + +接下来说下函数组件,hooks之前,函数组件就是单纯的ui组件,hooks引入过后函数组件就可以做到同类组件相同的事件了。hooks使用相当于在之前函数组件的基础上加入了一些状态函数的调用,常见的hooks如下: + +- useState:定义一个状态的变量,返回使用和修改的变量。这个hook就是对应类型的state功能 +- useEffect:入参1为函数,入参2为监听的变量数组,当监听的变量有改动时就会调用入参1的函数,具体使用可看官网。该hook就是对应了类组件中的生命周期了。 +- useCallback:入参1为函数,入参2为监听的变量数组,返回一个函数提供调用, 当监听的变量有修改就会修改返回的函数,通过这样可以做到函数的缓存 +- useMemo:类似useCallback,不过是缓存的值。 + +以上是一常用的hooks。通过这些hooks,函数组件可以做到和类型一样的事,同时代码更加简洁和清晰,因此现在基本都使用函数组件来进行开发。函数组件也更加锲合`F()=UI`,更能体现React的理念。 + +## React 的渲染机制 + +React 使用虚拟 DOM来优化真实 DOM 的更新。每次状态变化时,React 通过重新渲染组件生成新的虚拟 DOM,并与旧的虚拟 DOM 进行 Diff 比较,最终最小化真实 DOM 的更新。 + +深入理解: + +- 虚拟 DOM:它是 React 使用的一种数据结构,表示 UI 的当前状态。通过 React.createElement 方法创建节点树。 +- Diff 算法:React 使用的 Diff 算法通过最小化计算量找到需要更新的地方。掌握这些算法有助于理解为什么有些复杂 UI 操作可能导致性能问题。 +- 渲染优化:使用 shouldComponentUpdate(类组件)或 React.memo(函数组件)来避免不必要的渲染。 + +虚拟DOM就是对真是的dom数做的一层抽象展示,通过js对象来模拟这棵树,当用户操作后页面需要改动时,会再次生成一个更新后的数,然后使用diff算法来找到需要更新的地方,最后对页面上的dom进行操作,以此来完成更新。这些都是框架内部的操作,React已经做好了优化,开发者能做的是在生成这课新的dom树的过程中进行优化,也就是具体代码的优化。 + +比如类组件的`shouldComponentUpdate`方法,入参为下一次的`Props`,`State`等数据,通过返回`True` or `False` 判断组件是否更新。在函数组件中也有优化的手段,比如 + +- useCallback,缓存函数 +- useMemo,缓存值 + +除了上面的一些点,还有就是函数组件本身的优化。每一次state的变更,函数组件就会像执行函数那样重新执行该组件,组件内部的声明变量也会重新构建,上面的那些优化hook也就可以用起来了,同时子组件也会重新执行,这个时候无论子组件做了什么优化都会重新执行子组件,所有在进行代码拆分时尽可能的减少父组件的state。 + +## 代码分割和懒加载 + +对于大型应用,代码分割和懒加载是优化加载时间和提升性能的重要策略。React 提供了 React.lazy 和 Suspense,帮助你实现按需加载组件。 + +实现方法: + +- React.lazy:将组件懒加载,避免在初始加载时加载过多的代码。 +- React.Suspense:为懒加载组件提供占位符,直到组件加载完成。