当前位置: 首页 > Web前端 > HTML5

更简洁易用的react数据流near-react

时间:2023-04-05 18:38:01 HTML5

Nearly是一个简洁而强大的数据流框架;Github安装npminstall--savenearly-react功能。上图为flux架构图。Nearly参考了flux,并在其基础上做了如下简化和改进:功能:集成Promise,我们不再需要额外编写componentDidMount方法来异步获取数据。更多情况下,我们会使用无状态组件,让代码更简洁;Store的使用更加灵活,Store的单实例和多实例的使用可以巧妙地实现跨组件的通信复用和通用的组件控制逻辑;相比flux:API更简洁,业务中一般只使用connect和dispatch方法;集中管理状态,类似于原来的React,学习和迁移成本低;更轻量级,min后仅6K;使用示例importReactfrom'react';import{render}from'react-dom';import{connect,dispatch,registerStore}from'nearly-react';registerStore('counter',{//初始化方法必须是实现后,它将被隐式调用以初始化状态init(){return{count:0};},add(getState,step){return{count:getState().count+step};}};letincr=()=>dispatch('counter::add',1);letdecr=()=>dispatch('counter::add',-1);functionCounter(props){return(

-{props.count+
)}letHocCounter=connect('counter',Counter);render(,document.getElementById('root'))APIregisterStore(storeName,dispatcherSet)这个方法会注册一个Store。需要注意的是这个方法必须先执行,例如:registerStore('customStore',{//必须实现初始化方法init(){return{sum:0};},add(getState,num){return{sum:getState().sum+num};}});registerStore方法接受的第二个参数Dispatcherfunctions(getState,...args)就是Dispatcherfunctions;Dispatcher函数的第一个参数是getState方法,总是返回最新的状态,其余参数为dispatch方法传递的参数;对于Dispatcher函数的返回值:当是普通对象时,return值直接合并到旧状态;当是Promise时,取Promise.prototype.then方法中的参数合并到旧状态;为null时,不合并,不触发render;example:registerStore('counter',{//必须实现init方法,Promise也可以在init中使用init(){returnfetch('./test.json').then(res=>res.json());},添加(getState,step){return{count:getState().count+step};},//异步增加addAsync(getState,step){returnnewPromise(resolve=>{setTimeout(()=>{//getState方法总是返回最新的状态letcount=getState().count+step;resolve({count})},1000);});},//不触发渲染nothing(getState,step){returnnull;}};dispatch(action,...args)默认配置的action格式为${storeName}::${function},dispatch会根据action映射到对应的Dispatcher函数,args会传给Dispatcher函数作为参数,将返回结果提交给Store,Store触发组件更新;connect(storeName,Component[,PlaceHolder,isPure])该方法会根据storeName获取Store,然后将Store、Component和PlaceHolder组合起来返回一个高层组件;其中,PlaceHolder是默认显示组件(可选),仅在init返回Promise时有效,在Component插入dom之前,组合的高阶组件会先显示PlaceHolder组件,可以用来实现这样的效果作为装载;但是当组件太大时,可以通过将isPure设置为true来提高性能。当设置isPure为true时,只有dispatch方法可以触及发送组件的渲染,我相信这比在shouldComponentUpdate中写shallowEqual有效得多;您还可以通过以下配置将默认的isPure设置为true;advancedusedispatcher(action,...args)是高级调度函数;示例:dispatch('counter::add',1);等同于:dispatcher('counter::add')(1);派遣('test::testAdd',1,2,3,4);它等同于:dispatcher('test::testAdd',1,2)(3,4);configure(option)几乎用于开发,我们需要考虑重复的storeName,我建议将storeName映射到文件路径避免;nearly提供了两个可配置的方法:beforeConnect和beforeDispatch;beforeConnect会在调用connect方法之前调用,接受的参数是传递给connect方法的storeName;我们可以使用它来加载相应的JS文件,并注册Store;beforeDispatch会在调用dispatch方法之前被调用,接受的参数是传递给dispatch方法的action;默认配置如下:import{registerStore,getStore}from'./store';letconfig={//defaultisPuredefaultPure:false,//默认不启用自动注册StorebeforeConnect(storeName){//letstore=getStore(storeName);//if(!store){//让realName=storeName.split('#')[0];//registerStore(storeName,require(`./actions/${realName}.js`));//}},beforeDispatch(action){let[storeName,dispatcherName]=action.split('::');letstore=getStore(商店名称);if(!store){throwError(`store'${storeName}'不存在`);}让dispatcher=store.dispatchers[dispatcherName];if(!dispatcher){throwError(`模块不导出函数${dispatcherName}`);}return{store,dispatcher};}}使用示例:import{configure,getStore,registerStore}from'nearly-react';configure({beforeConnect(storeName){//配置beforeConnect方法,当store不存在时自动注册Store//自动转到加载JS模块并注册Store的操作目录letstore=getStore(storeName);if(!store){letrealName=storeName.split('#')[0];registerStore(storeName,require(`./动作/${realName}.js`));}}});同一个Store单实例在业务中,我们经常需要跨组件通信,或者组件之间共享数据;使用Nearly,我们可以轻松地将两个不同的组件绑定在一起Store,只要传递给connect的storeName相同即可;例子:简单输入同步显示registerStore('vm',{//必须实现init方法,会被隐式调用,作用是初始化状态init(){return{value:''};},change(getState,value){return{return{value};};}};///components/Input.jsletchange=e=>dispatch('vm::change',e.target.value);functionInput(props){return}exportdefaultconnect(Input,'vm');///components/Text.jsfunctionText(props){返回

{props.value}

}exportdefaultconnect(Text,'vm');详见示例:One-store同一个Store的多个实例,我们在开发通用组件时会用到同一个store的不同实例需要绑定同一个组件复用;可以通过在storeName中添加#id来区分不同的Store;//Dialog.jsexportdefaultfunctionDialog(props){return
{props.content}/div>}letDialogA=connect(Dialog,'dialog#a');letDialogB=connect(Dialog,'dialog#b');//关闭弹窗Adispatch('dialog#a::close');//关闭popupBdispatch('dialog#b::close');笔记注意,在组件内部使用dispatch时,storeName可以由props._storeName决定;具体见示例:DialogexampleTodoMVCCounterDialogOne-storeReact-SPA-SeedTipsnearly-config.js必须在业务逻辑之前加载;虽然有registerStoreAPI,但作者还是推荐使用connect来隐式注册Store,因为connect是通过storeName映射文件注册Store,在保证唯一性的同时更容易维护和调试;Nearly中对Promise的判断是不准确的(只要有then方法的都认为是Promise实例),一方面是因为Nearly中只使用了then方法,另一方面是为了兼容与jQuery.Deferred和其他类库;欢迎提交issue或pr;