后台React是一个非常优秀的UI库。一开始,React只专注于UI层,对于全局状态管理并没有很好的解决方案,催生了Flux、Redux等优秀的状态管理工具Produce,久而久之又催生了一批新的状态管理工具。管理工具。简单梳理一下目前主流的一些状态管理工具:ReduxReactContext&useReducerMobxRecoilreact-sweet-statehox这些都是我接触过的,Npm上的现状和趋势对比:毫无疑问,React和Redux的结合是目前主流。五月的今天,一个叫Recoil.js的新成员进入了我的视野,带来了一些有趣的模型和概念。今天我们就把它和Redux做一个简单的对比,希望对大家有所启发。先看文中的Redux:ReduxReact-Redux架构图:这个模型比较简单,大家也比较熟悉。先用一个简单的例子,回头看下整个模型:actions.jsexportconstUPDATE_LIST_NAME='UPDATE_NAME';reducers.jsexportconstreducer=(state=initialState,action)=>{const{listName,tasks}=state;switch(action.type){case'UPDATE_NAME':{//...}default:{returnstate;}}};store.jsimportreducersfrom'../reducers';import{createStore}from'redux';conststore=createStore(reducers);exportconstTasksProvider=({children})=>({children});App.jsimport{TasksProvider}from'./store';importTasksfrom'./tasks';constReduxApp=()=>();Component//componentsimportReactfrom'react';import{updateListName}from'./actions';importTasksViewfrom'./TasksView';constTasks=(props)=>{const{tasks}=props;返回();};constmapStateToProps=(state)=>({tasks:state.tasks});constmapDispatchToProps=(dispatch)=>({updateTasks:(tasks)=>dispatch(updateTasks(任务))});导出默认连接(mapStateToProps,mapDispatchToProps)(任务);当然你也可以使用connect,react-redux提供了两个hook,useDispatch和useSelector,也很方便从'react-redux'导入{useDispatch,useSelector};constTasks=()=>{constdispatch=useDispatch();constname=useSelector(state=>state.name);constsetName=(name)=>dispatch({type:'updateName',payload:{name}});返回();};整个模型并不复杂,redux也推出了redux工具包,提供了createSlice方法来简化一些操作,例如://ActionexportconstUPDATE_LIST_NAME='UPDATE_LIST_NAME';//ActioncreatorexportconstupdateListName=(name)=>({type:UPDATE_LIST_NAME,payload:{name}});//Reducerconstreducer=(state='Myto-dolist',action)=>{switch(action.type){caseUPDATE_LIST_NAME:{const{name}=动作.有效载荷;返回名称;}默认值:{返回状态;}}};导出默认减速器;使用createSlice://src/redux-toolkit/state/reducers/list-nameimport{createSlice}from'@reduxjs/toolkit';常量列表NameSlice=createSlice({name:'listName',initialState:'todo-list',reducers:{updateListName:(state,action)=>{const{name}=action.payload;returnname;}}});exportconst{actions:{updateListName},}=listNameSlice;导出默认listNameSlice.reducer;通过createSlice可以减少一些不必要的代码,提升开发体验。但是,Redux还是有一些天生的缺陷:概念多,脑力负担大。属性需要一个一个pick,计算属性需要依赖reselect。还存在魔术字符串等一系列问题,使用起来繁琐易错,开发效率低下。触发更新的效率也比较差。对于store连接的组件,必须一个一个遍历,然后组件进行比较,拦截不必要的更新。这对于性能导向或者大型应用来说无疑是一场灾难。对于这种情况,React本身也提供了一种解决方案,就是众所周知的Context.{value=>/*rendersomethingbasedonthecontextvalue*/>在父节点添加一个Provider,在子节点添加一个Consumer,但是每增加一个item就需要增加一层Provider,而且越来越多:而且,使用起来有很多问题语境。对于使用useContext的组件来说,最突出的问题就是re-render。不过也有相应的优化方案:React-tracked。一个小例子://store.jsimportReact,{useReducer}from'react';import{createContainer}from'react-tracked';从'./reducers'导入{reducers};constuseValue=({reducers,initialState})=>useReducer(reducer,initialState);const{Provider,useTracked,useTrackedState,useUpdate}=createContainer(useValue);导出constTasksProvider=({children,initialState})=>({children});export{useTracked,useTrackedState,useUpdate};对应的,还有一个hooks版本:const[state,dispatch]=useTracked();constdispatch=useUpdate();conststate=useTrackedState();//...RecoilRecoil.js提供了另一种思路,它的模型是这样的:在React树上再创建一个正交树,提取每一项的状态。每个组件都有对应的状态,当数据更新时,相应的组件也会更新。Recoil将每条数据称为一个Atom,Atom是一个可订阅的可变状态单元。这可能有点抽象,让我们看一个简单的例子://index.jsimportReactfrom"react";importReactDOMfrom"react-dom";import{RecoilRoot}from"recoil";import"./index.css";从"./App"导入应用程序;从"./serviceWorker"导入*asserviceWorker;ReactDOM.render(,document.getElementById("root"));RecoilRoot提供原子在其中具有值的上下文。必须是使用任何Recoil挂钩的任何组件的祖先。多个根可能并存;原子将在每个根中具有不同的值。如果它们是嵌套的,最里面的根将完全掩盖任何外部根。RecoilRoot可以看作是顶级的Provider。Atoms假设现在要实现一个计数器:首先用useState实现它:importReact,{useState}from"react";constApp=()=>{const[count,setCount]=useState(0);return(setCount(count+1)}>增加setCount(count-1)}>减少
Countis{count}
);};exportdefaultApp;然后使用atom重写:importReactfrom"react";从“反冲”导入{原子,useRecoilState};constcountState=atom({键:“计数器”,默认值:0,});constApp=()=>{const[count,setCount]=useRecoilState(countState);return(