待雾散开,自然能看到想要的风景。
我们都知道,JSX是React.createElement(component, props, ...children)的语法糖。
1  | class Hello extends React.Component {  | 
Diff算法
当组件的root为不同类型的diff
diffing如下
1  | <div>  | 
<Counter /> 会被卸载并且它的state会被销毁
同类型的DOM元素比较
1  | <div className="before" title="stuff" />  | 
React只改变className
1  | <div style={{color: 'red', fontWeight: 'bold'}} />  | 
React也只改变color
同类型的React组件
React不会卸载组件(即同一个JS instance),React会通过更新props去匹配新的DOM元素,之后调用componentWillReceiveProps() and componentWillUpdate()。
在Children中递归
1  | <ul>  | 
React能匹配first和second,并且保证这两棵子树的完整,只是插入third子树。
试想一下,如果third在first之前插入,React不会考虑first和second的完整性,而是改变每一个子节点。How a bad performance !
Key
key用来解决上面的问题
1  | <ul>  | 
Render Props
利用render props解决组件复用问题
一个简单的应用场景
需要记录鼠标移动的位置,并用p标签显示出来。
一般会直接封装一个Mouse组件用来记录鼠标的位置并且保存在state状态。并且通过this.state在p标签中显示。直接在MouseTracker(父组件中调用就可以了)。
但这并没有实现真正的封装,当我们新增业务需求的时候,比如需要随鼠标渲染出一只猫的image,创建一个Cat组件。把Cat组件放在Mouse组件的render()方法里,通过传入this.state来获取鼠标位置渲染出image。这样就失去复用的的意义了,如果要渲染Dog,Pig,那么每次都要重新创建Mouse组件,MouseWithCat、MouseWithPig、MouseWithDog。
利用render属性,可以实现动态渲染。
1  | class Cat extends React.Component {  | 
注意
(1) render Props的属性名不强制规定为render
(2) children prop也能实现
1  | <Mouse>  | 
(3) 小心用render属性
因为render属性是个函数,向下面这样写就很不好
1  | <Mouse render={mouse => (  | 
每次Mouse组件重新渲染的时候都会重新创建render函数。
将render函数作为组件实例方法就行了。(组件一般都会一直在内存里)
1  | class MouseTracker extends React.Component {  |