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

从小学数学谈前端框架设计

时间:2023-03-27 14:40:02 JavaScript

大家好,我是卡·小学生·宋。很高兴距离小学放暑假还有不到10天。当我被喷农药时,我会说:“妈妈只让我放假玩,我的手有点酸。”回到前端。其实前端框架是一个很简单的东西,大部分框架的工作原理用小学生的知识都能解释清楚。本文将从这些知识入手,逐步讲讲前端框架更新粒度背后的取舍。阅读本文后,您不仅可以获得审视不同框架的视角,还可以了解使用ReactHooks的原因。别再看不起我们这些小学生了!自变量、因变量和响应更新的小学知识是:自变量和因变量。对于以下等式:2x+1=yx是自变量,y的值受x的影响,x是因变量。在很多框架和状态管理库中,也有自变量和因变量。Vue3中的参数:constx=value(1);//取值console.log(x.value);//assignx.value=2;MobX的参数:constx=observable({data:1});//获取值console.log(x.data);//赋值x.data=2;React的参数:const[x,setX]=useState(1);//获取值console.log(x);//赋值setX(2);这些框架(或库)的参数由getter(值)和setter(赋值)组成。有了自变量,当然还有因变量。我们可以通过是否有副作用来区分。Vue的因变量://无副作用//赋值consty=computed(()=>x.value*2+1);//Valueconsole.log(y.value);//Sideeffectswatch(()=>文档.title=x.value);MobX的因变量://无副作用consty=computed(()=>x.data*2+1);console.log(y.get());//有副作用autorun(()=>document.title=x.data);React的因变量://无副作用consty=useMemo(()=>x*2+1,[x]);安慰。log(y);//有副作用useEffect(()=>document.title=x,[x]);有了自变量和因变量,结合描述视图的方式,就可以描述组件UI了。比如在React中,通过JSX来描述视图:const[x,setX]=useState(21);consty=useMemo(()=>x*2+1,[x]);return

我的记录是0/{x}/{y}

;加上各种允许用户操作自变量的事件,比如给p加上onClick:setX(x+1)}>我的记录是0/{x}/{y}

;最后添加少量的辅助钩子函数,如:组件出错时的钩子函数。构成一个功能齐全的组件。这是所有细粒度更新框架在底层的共同点:通过事件驱动变量变化,最终驱动视图(或副作用)变化。面向对象的痛我们刚开始学编程的时候,都学过一个概念——面向对象(下面简称OO),很容易接受一个设定——OO可以提高可读性和易维护性。原因:OO是对现实世界的模拟。例如:人类可以继承哺乳动物的属性。这是一种面向对象的模型,但实际上适得其反。回想一下,当你学习React的Class组件时,OO简单的外表背后是一个复杂的生命周期概念。先问大家几个问题:shouldComponentUpdate的原理是什么?componentWillReceiveProps什么时候触发?getDerivedStateFromProps中的derivedState是什么意思?幸运的是,React团队也意识到了这个问题,并着手进行更改。改变的结果是Hooks。使用Hooks的函数组件与Class组件最大的区别在于:从一个实例开始有了生命周期,变成了自变量、因变量和视图之间的映射关系。如果你接受了这个设定,想想现在主流的Hooks学习方式(连React官网也一样),原来是:用生命周期函数来比较Hooks的执行时机是不是很好笑?React在枷锁中跳舞的理想是美好的,但React底层并不是一个细粒度的框架。这在实现自变量和因变量时会造成很多限制。例如:Hooks调用的顺序不能改变(不能写在条件语句中)。比如,不知道大家有没有发现一个细节:React需要第二个参数,明确指出它的自变量是谁。例如:consty=useMemo(()=>x*2+1,[x]);useEffect(()=>document.title=x,[x]);相反,其他框架(或库)不需要它。例如,Vue:consty=computed(()=>x.value*2+1);watch(()=>document.title=x.value);为什么会有这些限制?我用两个比喻来解释。刚才讲了,在细粒度框架下,交互过程可以概括为:用户触发事件->自变量变化->因变量变化->映射到视图变化就像画家画画一样,绘画对应一个自变量变化,最后对应画面变化。React的更新机制大致概括如下:用户触发事件->触发更新->虚拟DOM全比对->将比对结果映射到视图操作就像一个人拿着相机拍照,然后把这张照片拍下来上次拍照找不同,终于更新了不同。当调用this.setState(或useState的setter)时,不是绘制下一个笔画,而是按下快门。如何从一张新照片中发现自变量?所以React只能比较新旧照片。一些陌生社区的人早就意识到了这个问题,于是Mobx诞生了。他带来了纯粹的细粒度更新能力。但是,这个能力是基于React的更新机制,就像:画家拿着画笔在画板上戳,他戳的是什么?按下相机快门。卡查拍了一张照片,艺术家将照片与旧照片进行了比较,然后将比较结果绘制在画布上。于是有人抱怨:为什么不直接用Vue配合React+Mobx呢?但是,Vue本身也依赖于虚拟DOM,而且粒度并不是最细的。更准确的说法应该是:SolidJS为什么不直接用React+Mobx?哎,过几天再说说纯细粒度更新框架(SolidJS)的实现原理。