当前位置: 首页 > 后端技术 > Node.js

流行的前端状态管理方案的选择:Redux-Mobx-Recoil

时间:2023-04-03 17:02:53 Node.js

对于前端开发来说,React状态管理方案的选择一直是核心问题之一。从近几年的下载量对比图来看,最流行的三种解决方案分别是Redux、mobx和recoil。本文首先讨论了对状态管理的理解,然后梳理比较了上述三种最主流的状态管理方案的使用方法和优缺点,并着重介绍了使用Recoil进行原子状态管理的优缺点。新时代。背景知识:状态和状态管理什么是状态?先说状态是什么。以前端接触最多的表单状态和UI状态为例。一个表单可以有多个状态,例如加载、提交和验证。表单中的内容也有多种状态,比如单选按钮(选中和未选中)、输入框(是否选中/是否有内容)等,这些状态是渲染和交互必不可少的因素,所以状态可以简单理解为我们渲染UI和处理交互的必备工具。为什么需要状态管理?对于一个比较复杂的React项目,整个页面需要各种状态来维护数据的交互和展示。React的基础状态管理只能管理当前组件中的状态,或者处理比较简单的组件间交互(父子/兄弟)。当涉及到组件之间更复杂的数据交互时,处理逻辑会变得非常复杂和不便。因此需要状态管理解决方案等工具来实现统一管理。当需要管理的数据量非常大时,一个好的状态管理方案可以起到事半功倍的效果。状态管理数据共享的本质在组件之间优雅高效地共享数据一直是各种状态管理方案所追求的不变目标。全局还是局部:实现数据共享最简单粗暴的方式就是实现全局共享。这也是Redux提供的解决方案。Redux的广泛应用逐渐在用户中形成了共识:React状态分为两种,一种是Redux管理的全局状态,一种是组件内部使用的局部状态(useState)。但其实我觉得局部状态的对立面不应该是全局状态,而是共享状态。全局状态共享只是实现共享状态的一种方式。另一种实现共享状态的可靠方法是本地状态共享。比如React本身提供的ContextAPI实现了一个组件树,在这个组件树上实现了状态共享,而不是在整个项目上共享数据。这种共享方式与全局状态共享方式相比,具有自我管理、拥有生命周期的优点。逻辑组织和状态管理的另一个关键点是如何组织一系列与数据相关的逻辑。针对这个问题,Hooks提供了比较完善的管理和组织解决方案,比如:状态副作用、性能优化、异步处理等。Hooks的出现极大的改善了组件内部的逻辑组织。我们不再需要盲目地将状态抽取到全局组织(比如Redux),而只需要关注当前状态的使用者是谁。多个,至于如何使用和组织组件内部的state,交给Hooks去处理就可以了。状态管理方案选择目前状态管理的代表性方案有:Redux、Mobx、Recoil,新一代原子化状态管理,各自代表不同的数据共享方式;Redux:FLux风格的单向数据流,SingleStore清晰易懂;Mbox:ResponsiveMultiStore,使用灵活,多个Stores相互隔离;Recoil:原子单向小循环,简单易用,可扩展性高;ReduxRedux是目前使用最多的状态管理库,其设计初衷是为了解决越来越复杂的单页应用状态管理。Redux的使用有3个原则:单一数据源、只读状态、纯函数执行修改。单一数据源:是指项目的全局状态存储在单个Store中的对象树中,提供读写操作;State是只读的:不能直接修改Store中的state,修改State的唯一方式是发送一个Action,触发相应的修改操作;纯函数执行:Action触发修改依赖于Reducer纯函数,Reducer会接收State和对应的Action,并返回修改后的新State;核心思想Redux的核心操作是对全局状态StateWrite进行读取和求和。下面展示了Redux完整的数据流。我们可以直接从全局State中读取渲染UI所需的状态,UI上会触发各种事件(点击等)来修改全局State。这是基本的读写逻辑。.修改状态需要几层处理。修改请求首先被Dispatch捕获并传递。每个修改操作都会传递一个初始状态和修改后的操作动作。通过的下一层是Reducer。Reducer是唯一执行修改的执行者。它根据接收到的初始状态和修改操作Action,在内部返回修改后的State,并将最新的State更新到全局。这是完整的核心逻辑。Middleware的加入进一步分离了与状态相关的异步操作。在Reducer处理之前,先完成Action中的异步操作(比如API请求),处理逻辑更加清晰。优缺点优点:全局状态管理,单向数据流清晰严格;统一规范的代码风格,适合团队开发缺点:状态太多非常臃肿,可能会导致性能问题;适用:中大型复杂项目的数据流管理;MobxMobx的目标是实现简单、可扩展的状态管理,它通过透明的函数式反应式编程来实现。和Redux一样,Mobx也是通过Action修改状态,然后将修改映射到可视化的Views上。区别在于:响应式双向数据绑定,而Redux是Fl??ux流派的单向数据流。观察者模式,当状态发生变化时,所有的衍生品都在原子级别自动更新。因此永远观察不到中间值。Mobx是multi-Store和可读可写的,而Redux是唯一的中央Store,只支持读操作。核心思想具体来说,Mobx的核心主要包括三个点:State(状态):多存储数据源,mobx也支持单Pass到数据流;推导(Derivation):任何源于状态且没有任何进一步交互作用的东西都是推导。Mobx有两种推导形式:ComputedValues——可以使用纯函数从当前可观察状态推导出的值;Reactions-Reactions是状态改变时需要自动发生的副作用,也使用了更多的衍生物;Actions(动作):Actions是唯一可以修改State的入口;总体来说,Mobx的去中心化Store和双向数据流设计可以让状态管理更加灵活和适用,但是这种灵活性也给实际开发带来了挑战。用户需要注意Store各部分的处理逻辑,可能会造成混淆。另外,虽然Mobx在中小型项目中表现不错,但面对大型复杂的应用场景,使用Mobx必须伴随着严格的规范。优缺点优点:上手容易,扩展性强,使用灵活。在性能上也有一定的优势。多个store源相互独立,无需关注副作用。更少的代码大小,没有像Redux样板代码那样的限制。缺点:过于自由,灵活使用的背后是缺乏规范的代码,导致团队的代码风格不一致。因为没有办法标准化和统一,所以不适合大而复杂的项目。适用:场景灵活的中小型项目。Recoilgithub地址:https://github.com/facebookex...官网:https://recoiljs.org/zh-hansRecoil简介Recoil是Facebook开发的用于React项目状态管理的状态管理库。Recoil定义了一个有向图,它是正交的,但自然地连接到你的React树。状态变化从该图的顶点(我们称之为原子)开始,并通过纯函数(我们称之为选择器)流向组件。具体来说,Recoil为消费者创建了一个数据流图,从原子(共享状态)到选择器(纯函数),再到React组件。所以核心是两部分:Atom是组件可以订阅的状态单元,Selector可以同步或者异步改变这个状态。特点:原子状态管理模式按需渲染读写分离代码实现安装Recoilnpminstallrecoil//oryarnaddrecoilRecoilRoot初始化:一般将RecoilRoot放置在父组件的根组件,代表其内部组件使用Recoil数据流。这样我们就可以直接在CharacterCounter组件中使用Recoil了。importReactfrom'react';import{RecoilRoot,atom,selector,useRecoilState,useRecoilValue,}from'recoil';functionApp(){return();}Atom:在反冲中用原子来表示状态,一个原子代表一个状态,在任何组件中都可以直接读写。更新任何原子的状态也会导致所有使用该原子的组件重新渲染。例如。下面是一段文本数据,key对应状态的唯一表示,default为默认值,调用未赋值时使用。consttextState=atom({key:'textState',//唯一ID(相对于其他原子/选择器)default:'',//默认值(又名初始值)});Selector:Selector可以用在ReocilDerived状态中,即状态转换。派生状态可以被认为是将初始状态传递给处理状态的纯函数的输出。Selector的强大之处在于它允许我们创建一个依赖于其他数据变化的动态数据。比如我们想获取一个过滤后的todo列表,那么我们可以在初始的todo列表FilteredSelector的基础上绑定一个特殊的todo列表来获取过滤后的动态列表。例如。下面是将过滤器Selector绑定到一个初始原子列表的操作。我们可以直接使用filteredTodoListState获取过滤后的数据:})=>{constfilter=get(todoListFilterState);constlist=get(todoListState);switch(filter){case'ShowCompleted':returnlist.filter((item)=>item.isComplete);case'Show未完成':returnlist.filter((item)=>!item.isComplete);default:returnlist;}},});本人曾使用Recoil参与过项目的开发。从我个人的体验来看,Recoil还是有很多优点的,比如简单易用,读写逻辑清晰,渲染高效,扩展性强。但相对来说,在使用过程中也暴露出一些问题。首先是API调用过多。一个状态从申报到使用需要经过六七个API。API总数达到了19个,每个atom中的statekey和default都必须先定义好才能使用,这无疑是繁琐的。另外我在使用过程中遇到了一个问题,就是selector中的异步请求干扰了页面元素的默认行为。具体的,我在Selecor中定义了请求数据的接口,在页面渲染的时候请求,但是同时在一个组件里面放了一个Input框,加上autofocus属性。由于Recoil的处理机制,异步请求的处理会影响Input,无法自动选择。解决方案是让选择器中的请求在渲染其他内容之前得到结果。因此,Recoil高效的渲染性能背后还存在一定的隐患,需要时间去验证。优缺点优点:简洁、优雅、可扩展避免无效渲染、高效细粒度的状态拆分也能为开发者带来更可维护的编码风格;缺点:繁琐的API调用选择器缺乏对副作用的处理没有时间修正使用中存在隐患适用:都适用用于灵活场景的中型项目。对于复杂的大型项目,之前的选择大多是Redux,因为它有更好的开发模板和规范。而现在更多的开发者愿意尝试使用Recoil来开发项目,因为Recoil非常兼容React的使用,并且在渲染性能和可扩展性等各方面也有优势。我相信没有什么缺点。以后会不断补货。