组件化和react
说一下对组件化的理解
组件化的核心有两点:
- 组件的封装
- 组件的复用
那些需要封装?首先是视图。一个组件的定义中,视图是首要的;其次是数据;最后是变化逻辑,即数据如何驱动视图变化。
而对于组件的复用,每次复用的是这个模板,并传递不同的属性过去。那么其重点就是props传递。
JSX本质是什么?
JSX解析成JS
JSX语法根本无法被浏览器所解析,那么它是如何在浏览器中运行的?简单来说,就是被解析成了JS。
解析过程用一个例子来解释:
看一下React.createElement,这是React中定义好的一个函数,第一个参数是标签名,第二个参数是属性,第三个参数可以是个数组,包含了所有的子元素,也可以是直接把子元素放在第三个参数开始的位置,即下面的用法:
那么第一个例子就是用了第二种用法,从第三个参数开始就是子元素。再看另外一个例子
这就是另外一种用法,第三个参数是数组,里面包含了所有子元素。
在另外一篇文章 vdom和vue 中,讲了vdom的两个核心函数,h函数和patch函数,那么这里的React.createElement函数就和h函数是类似的,和vue中的_c函数也是类似的。
那么总结一下,JSX其实就是一个语法糖,在开发环境下会将JSX编译成JS代码。
JSX的写法出现,大大降低了学习成本和编码工作量,但是同时,JSX也会增加debug成本。
独立的标准
JSX是React引入的,但不是React独有的。React已经将它作为一个独立标准开放,其他项目也可用。而React.createElement是可以自定义修改的。
JSX的本身功能已经晚辈了,和其他标准兼容和扩展性没问题。
JSX和vdom
首先为什么需要vdom?
vdom就是React初次推广开来的,结合JSX。而JSX其实就是模板,最终要渲染成html。
其次react需要通过数据驱动视图,JSX需要转换为JS代码,JS在这种数据驱动视图的场景下不能亲自操作dom,需要一个中间层——vdom。
需要渲染成html的两个场景包括初次渲染和修改state后的re-render重复渲染。
其次,在上面我们讲过了,react里,React.createElement相当于vdom中的h函数,如下
可以知道,所有jsx都会被转换为js代码来执行,其次,上图中的profile会返回vnode。
接下来就是patch,何时patch?
初次渲染时间就是使用ReactDOM.render(<App/>, container)函数的时候,此时会触发patch(container, vnode);
之后的re-render触发则是在使用setState修改state时,会触发patch(vnode, newVnode)
自定义组件的解析
如果在react中定义了组件,那么会这样解析
在ReactDOM.render的第一个参数中就是该组件的构造函数。
自定义组件的解析过程如下:
- ‘div’ - 直接渲染即可,vdom可以做到
- Input和List是自定义组件(class),vdom默认不认识
- 因此Input和List定义的时候必须声明render函数
- 根据props初始化实例,然后执行实例的render函数
- render函数返回的还是vnode对象
这里详细解释一下3、4步
以List为例子:
当渲染List的时候,通过data属性里的数据初始化一个List(class)的实例,这个实例实际上就是render函数返回的vnode对象
因此,上面的过程类似于如下代码:
setState
说一下React setState的过程
重点1:setState是异步的。这里顺带一提,vue修改属性也是异步的。
重点2: setState的过程
首先举个例子证明setState是异步的:
可以看到,在setState后马上打印this.state.list的值是仍为变化的值,只有在异步的情况下才有这种结果
那为何setState需要异步?第一,可能会一次执行多次setState;其次,无法规定、限制用户如何使用setState;没必要每次setState都重新渲染,考虑性能;另外,即便是每次重新渲染,用户也看不到中间的效果。
因此使用异步,将state统一执行即可。
例子如下:
在这里,只需要执行最后一个setState的渲染就可以了。
vue修改属性也是异步的原因和setState是一样的。修改vue属性,被响应式的set监听到,然后set中执行updateComponent,updateComponent重新执行vm._render函数,生成的vnode和prevVnode通过patch对比,渲染到html中
在set中执行updateComponent是异步的,在这里和react是类似的。
现在开始说setState的过程,首先每个组件实例,都有一个renderComponent的用法,继承于父类Component,执行renderComponent会重新执行实例的render,即重新返回一个新的vnode,newVnode和preVnode执行patch函数。
下一篇:虚拟dom