类库
快来分享你的内容吧~
最后一次系统的学习 React 状态管理库 Dva,
## React 状态管理 之 Dva 最近在做需求的时候,需要使用到一个状态管理库来对多个组件共同状态进行统一管理,React 的状态管理库其实是有很多的,例如:最简单的 React Context ,到经典的 Redux,Mobx,再到 Hooks 时代的新起之秀:Recoil(我写的简介:https://www.codefather.cn/post/1648709562175377409)还有很多优秀的库,可以看这篇:https://juejin.cn/post/7195513281228898363#heading-27 接下来,我会按照下面思路写这篇文章: 1. 什么时候需要使用状态管理库? 2. 为什么选择状态管理库 Dva ? 3. 什么是 Dva ? 4. 怎么使用 Dva ? 5. Dva 核心思想 > 本文对一些分支知识点也进行记录,大家可以自行寻找需要阅读的地方 ### 一 ,什么时候需要使用状态管理库  因为 React 是 **单向数据流**(数据的流动方向总是从父组件向子组件),当我们想要**多个组件共享一个状态**的时候,我们就会发现我们需要一个存状态的地方,方便状态被多个组件读取,更新。这里介绍一下官方的解决方案 ,使用 **Context** 将它保存在更上层组件的组件中,使用 **Provider** 将值传递给下面的树,任何组件都可以读取它。这里它的缺点有以下几个: 1. **组件的复用性降低:**如果一个组件依赖于某个 context,那么这个组件只能在这个 context 存在的地方使用。这可能会限制组件的复用性。 2. **难以进行状态管理:**当需要管理的状态变得复杂时,只使用 Context 可能会变得困难。例如,如果需要管理一个全局状态,同时还需要进行异步操作,那么可能需要引入额外的库(如 Redux 或 MobX)。 3. **性能问题:**当一个 Context 值改变时,所有消费这个 Context 的组件都将重新渲染,无论这个改变是否会影响到它们。如果有大量的组件订阅了同一个 Context,可能会引发性能问题。 4. **代码结构问题:**过度使用 Context 可能会导致代码结构混乱。有时候很难确定哪个部分的代码应该放在 Context Provider 中,哪个部分的代码应该放在 Context Consumer 中。 5. **不易于调试:**与 Redux 相比,Context API 的调试工具不够强大。如果状态传递链很长或者很复杂,问题定位和调试可能会比较困难。 这些问题在面对复杂状态管理,异步状态更新的情况下,会变得极为棘手,于是社区就产生了很多优秀的状态管理库来解决问题 我们还会在 - **复杂的用户交互**:例如多个视图之间的跳转,多个组件之间的交互等,使用状态管理库(提取 UI 交互控制状态)可以帮助你更好地管理这些交互。 - **大型项目:**对于大型的、复杂的项目,状态管理库可以帮助你更好地组织代码,使代码更易于理解和维护 - **异步操作:**如果你的应用需要处理很多异步操作,例如网络请求,状态管理库可以帮助你更好地处理这些操作。 - **跨组件通信:**如果你的组件树结构复杂,父子组件或者兄弟组件之间需要频繁通信,那么使用状态管理库可以简化这种跨组件的通信。 **重点**:并不是所有的 React 项目都需要使用状态管理库。对于一些小型的、简单的项目,React 自带的状态管理(useState 和 useReducer hooks)可能已经足够了。引入过度复杂的状态管理库可能会导致代码变得更复杂,更难以理解和维护。引入复杂的状态管理库是为了解决 1. 更加复杂的逻辑, 2. 简化代码, 3. 便于代码维护 4. 提高代码可读性 而不是为了让代码变得更糟糕 ### 为什么选择状态管理库 Dva ? 我在开发的项目是基于 umi 3 搭建的,所以如果选择状态管理工具,那一定就是自带的` @umijs/plugin-dva ` 插件,如果我的项目是 next.js 搭建的,我应该会选择 Recoil ,因为它的代码更加简洁,方便阅读。 不过,Dva也是一个很优秀的状态管理库,尤其是在大型项目中,它强制的规范了代码的书写方式,这样代码更加方便维护,因为规范代码在多人开发的大型项目是极为重要的,因为每个程序员都有自己的偏好代码书写方式, 这里,还有一个问题,就是 umi 3 是有两个内置的状态管理插件的 ,分别是刚刚提到的`@umijs/plugin-dva` 和 更加轻量的`@umijs/plugin-model `。那如何选择呢? 1. **@umijs/plugin-model:**这是 Umi 3 中的一个新特性,是一种基于 hooks 的轻量级全局状态管理方案。plugin-model 以文件为单位进行状态管理,对于每个 model 文件,内部会自动创建一个独立的 React context。并且在使用时,不需要 dispatch,直接使用 actions 即可。**最佳实践:**@umijs/plugin-model 更适合在项目中快速、轻量级地管理全局状态。它没有繁琐的概念,API 极简,适合小到中型项目。此外,它基于 React hooks,如果你的项目已经或者准备使用 React hooks,@umijs/plugin-model 会是一个不错的选择。 2. **@umijs/plugin-dva:**这是将 DVA 集成到 Umi 3 中的插件,使用了 Redux、Redux-saga、React-router 等技术进行状态管理。DVA 是一种更完整的状态管理方案,包含了 action、reducer、effects 等概念。**最佳实践:**@umijs/plugin-dva 更适合在大型复杂项目中进行状态管理。它有完善的概念和方法,可以处理复杂的异步操作和副作用。如果你的项目中有复杂的状态管理需求,或者项目团队已经习惯了 Redux 的开发模式,那么 @umijs/plugin-dva 会是一个更好的选择。 总的来说,`@umijs/plugin-model` 和 `@umijs/plugin-dva` 的主要区别在于其复杂度和应用场景。plugin-model 更简单、更轻量级,适合小到中型项目,它也更加自由,代码更加不可控,而 plugin-dva 更复杂、更强大,适合大型复杂项目,它的约束更多,代码更加规范。 ### 什么是 Dva ? 我认为 Dva 最好的介绍文档,就是它的官网:https://dvajs.com/ ,它是由 蚂蚁 的前端大佬 sorrycc 写的, dva 首先是一个基于 [redux](https://github.com/reduxjs/redux) 和 [redux-saga](https://github.com/redux-saga/redux-saga) 的数据流方案,然后为了简化开发体验,dva 还额外内置了 [react-router](https://github.com/ReactTraining/react-router) 和 [fetch](https://github.com/github/fetch),所以也可以理解为一个轻量级的应用框架 我觉得Dva 产生的原因有 3 个, 1. **简化 Redux 的使用**:Redux 是一个非常强大的状态管理工具,但是它的使用相对复杂,需要写很多模板代码。例如,你需要定义 actions,reducers,然后再将它们关联起来。DVA 对 Redux 进行了封装,让开发者可以更简单地使用 Redux。 2. **处理异步操作**:Redux 本身并不支持异步操作,通常需要使用中间件如 Redux-thunk 或 Redux-saga 来处理。DVA 内置了 Redux-saga,使得处理异步操作变得更简单 3. **集成路由**:在传统的 React + Redux 应用中,路由和状态管理通常是分开的。DVA 将 React-router 集成进来,使得路由和状态管理可以一体化处理。 当然,它还提供了 插件系统,遵循 Elm 架构, **这里讲一下 Elm 架构** Elm 架构是一种用于构建前端应用的架构模式,它起源于 Elm 语言,但已被许多其他的前端框架和库所采纳,包括 Redux 和 DVA。 Elm 架构主要包含以下几个部分: 1. **Model**:模型代表了应用的状态。在一个计数器应用中,模型可能就是一个数字;在一个待办事项列表应用中,模型可能是一个代表待办事项的数组。 2. **Update**:更新函数定义了如何根据接收到的 action 更新模型。它接收当前的模型和一个 action,然后返回一个新的模型。这个过程是纯函数,即同样的输入总会得到同样的输出,没有副作用。 3. **View**:视图函数负责根据模型生成 UI。它接收模型作为参数,然后返回一些描述 UI 的代码(在 Web 开发中,通常是 HTML 或 JSX)。 4. **Actions**:动作描述了用户或系统可能对应用做的操作。例如,在一个计数器应用中,可能有 "增加" 和 "减少" 两种操作。 在 Elm 架构中,数据流是单向的:用户或系统通过触发动作来修改模型,然后更新函数根据动作和当前模型计算出新的模型,最后视图函数使用新的模型生成新的 UI。 这种单向数据流使得应用的状态变化变得可预测和易于理解,也更便于调试和测试。因此,Elm 架构已经被广泛应用于前端开发中。 ### 怎么使用 Dva ? > 参考链接:https://dvajs.com/guide/getting-started.html 我觉得最好学习 Dva 的方式就是自己写一个小 demo,例如:写一个需要状态共享,代码逻辑可以提取的小系统,先不使用任何状态管理库去实现,然后再用 Dva 实现,你会深刻体会到它的作用,它解决了什么问题。最好通过这个demo体验它的所有功能,然后再去看 Dva的概念,加深对状态管理库 Dva 思想的理解 ### Dva 核心思想 > 参考链接:https://dvajs.com/guide/concepts.html  在 DVA 中,所有的数据流都遵循同样的模式:首先,用户交互或者其他事件触发 action;然后,saga 中间件捕获这个 action,并可能触发异步操作,如数据请求;最后,根据 action 的类型,对应的 reducer 将会更新状态。 DVA 还引入了 Model 的概念,将 Redux 中的 reducers、effects 和 subscriptions 集合在一起,使得相关的代码更加集中和模块化。通过这种方式,DVA 使得状态管理的逻辑更加清晰,更易于理解和维护。 此外,DVA 还内置了路由管理功能,提供了基于路由的动态加载机制,使得大型应用的状态管理和路由管理可以统一处理。 ### 注意事项 & 经验 1. **合理设计 Model**:在 DVA 中,Model 是核心的部分,对应的就是你的数据模型。一个好的 Model 设计应该是简单并且易于理解的,避免过度复杂的状态设计。 2. **保持 Reducer 的纯净**:Reducer 是一个纯函数,它不应该产生任何副作用。在 Reducer 中,你不能直接修改传入的 state,而是应该返回一个新的 state,这样也符合React 的不变性,但是如果你觉得麻烦,可以通过 3. **尽量减少 state 的复杂性**:尽量保持 state 的扁平化,避免过度的嵌套结构。这样可以使 state 更容易理解和操作。 4. **善用 Effects**:Effects 是 DVA 中处理异步操作的地方。你可以在这里进行各种异步操作,如获取数据、延时操作等。 5. **合理使用 Subscription**:Subscription 可以用来监听数据源并根据需要 dispatch action,但并不是所有的 action 都需要通过 Subscription 来触发。在某些情况下,直接在组件中 dispatch action 会更加方便和直观。 6. **注意性能优化**:在编写代码时,你应该注意避免不必要的渲染和状态更新,以提高应用的性能。 7. **遵循单一职责原则**:每个 Model 应该只负责管理一部分状态,每个 Component 应该只负责渲染一部分 UI。这样可以使你的代码更加模块化,更易于维护。 8. **编写可测试的代码**:尽量让你的代码更容易进行单元测试。例如,你可以将业务逻辑尽可能抽取出来,使其不依赖于特定的组件或者环境。 9. 直接在 model 中监听 state 的变化可能会导致逻辑混乱,不易于维护,因此并不推荐这样做。 10. 在大多数情况下,你应该尽量在组件中监听 state 的变化,然后 dispatch action 来更新 state。 11. 我们应该把 更新状态 state 和 同步操作 都在 Reducer 中实现,把异步事件,接口请求都在 Effect 中实现, 12. 我们可以在 Subscription 中进行订阅数据源,数据源可以是 - 当前的时间 - 服务器的 websocket 连接 - keyboard 输入 - geolocation (用户的地理位置信息的变化)变化 - history 路由变化等等。 当数据源发生变化时,可以通过 dispatch 触发相应的 action,进而改变应用状态。
React Beautiful Dnd
地址:https://github.com/atlassian/react-beautiful-dnd
XSS
特性: - 白名单控制允许的HTML标签及各标签的属性 - 通过自定义处理函数,可对任意标签及其属性进行处理 地址:https://jsxss.com/zh/index.html
Axios 中文文档
Axios 使用简单,包尺寸小且提供了易于扩展的接口。 地址:https://www.axios-http.cn/
WebJars
地址:https://www.webjars.org/
React UseGesture
用于 React 中组件绑定鼠标/触摸手势的 Bread n butter 实用程序 地址:https://github.com/pmndrs/use-gesture
Flutter Awesome
地址:https://flutterawesome.com/
Bounce.js
地址:http://bouncejs.com/
anime.js
Anime.js (/ˈæn.ə.meɪ/) 是一个轻量的JavaScript 动画库, 拥有简单而强大的API。 可对 CSS 属性、 SVG、 DOM 和JavaScript 对象进行动画。 地址:https://www.animejs.cn/
Python Awesome
地址:https://pythonawesome.com/
