待雾散开,自然能看到想要的风景。
我们都知道,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 { |