- 本文是对于腾讯大佬写的半小时深刻理解react这篇文章的总结和笔记
文章目录
1.认识JSX
图示jsx到js的编译
2.虚拟DOM
- React会在内存中维护一个虚拟DOM树,当我们对这个树进行读或写的时候,实际上是
对虚拟DOM进行
的。 - 当数据变化时,然后React会自动更新虚拟DOM,然后拿新的虚拟DOM和旧的虚拟DOM进行
对比
,找到有变更的部分,得出一个Patch,然后将这个Patch放到一个队列里
,最终批量更新
这些Patch到DOM中。 - 这样的机制可以保证
即便是根节点数据
的变化,最终表现在DOM上的修改也只是受这个数据影响
的部分,这样可以保证非常高效的渲染。 - 但也是有一定的缺陷的——首次渲染大量DOM时因为多了一层虚拟DOM的计算,会比innerHTML插入方式慢。
3.认识react组件
- props主要作用是提供数据来源,可以简单地理解为props就是
构造函数的参数
。 - state唯一的作用是
控制组件的表现
,用来存放会随着交互变化的状态
,比如开关状态等。 - JSX做的事情就是根据state和props中的值,
结合一些视图层面的逻辑
,输出对应的DOM结构
。
实现组件化组装
例如要实现上方红色的功能:
- 先做article组件里面分为图片文字的初属性
- 然后做热点组件,左右框的显示中要调用article组件
- 然后后面的热问同样也调用了article组件
4.react数据流
在React中,数据流是自上而下单向地从父节点传递到子节点
,所以组件是简单且容易把握的,他们只需要从父节点提供的props中获取数据并渲染
即可。如果顶层组件的某个prop改变了,React会递归地向下遍历整棵组件数
,重新渲染所有使用这个属性的组件。
props属性和propsTypes格式校验
- props永远是只读的
- props的属性校验
state事件
这是一个简单的开关组件,开关状态会以文字的形式表现在按钮的文本上。
首先看render方法,返回了一个button元素,给button注册了一个事件用来处理点击事件,在点击事件中对state的on字段取反
,并执行this.setState()方法设置on字段的新值
。一个开关组件就完成了。
DOM更新的原理
这是一个React组件实现组件可交互所需的流程,
- render()输出虚拟DOM,
- 虚拟DOM转为DOM,
- 再在DOM上注册事件,
- 事件触发setState()修改数据,
- 在每次调用setState方法时,React会自动执行render方法来更新虚拟DOM,如果组件已经被渲染,那么还会更新到DOM中去。
5.组件的生命周期
初始化、更新和销毁
,在组件生命周期中,随着组件的props或者state发生改变,它的虚拟DOM和DOM表现也将有相应的变化。
初始化
1. 获取props初始值
组件类在声明时,会先调用getDefaultProps()
方法来获取默认props值,这个方法会且只会在声明组件类时调用一次
,这一点需要注意,它返回的默认props由所有实例共享。
2. 获取state事件
在组件被实例化之前,会先调用一次实例方法getInitialState()
方法,用于获取这个组件的初始state
。
3. 实例化之后渲染的准备工作
componentWillMount
方法会在生成虚拟DOM之前被调用,你可以在这里对组件的渲染做一些准备工作,比如计算目标容器尺寸然后修改组件自身的尺寸以适应目标容器
等。
4. render渲染
创建一个虚拟DOM
用来表示组件的结构。对于一个组件来说,render是唯一一个必须的方法。render方法需要满足这几点:
只能通过this.props或this.state访问数据
只能出现一个顶级组件
可以返回null、false或任何
React组件
不能对props、state或DOM进行修改
需要注意的是,render方法返回的是虚拟DOM
。
5. 渲染完成以后对DOM的后续操作
我们可能需要对DOM做一些操作,比如截屏、上报日志,或者初始化iScroll等第三方非React插件,可以在componentDidMount()方法
中做这些事情。当然,你也可以在这个方法里通过this.getDOMNode()方法最终生成DOM节点
,然后对DOM节点做爱做的事情,但需要注意做好安全措施,不要缓存
已经生成的DOM节点,因为这些DOM节点随时可能被替换掉,所以应该在每次用的时候去读取
。
组件被初始化完成后,它的状态会随着用户的操作、时间的推移、数据更新而产生变化,变化的过程是组件声明周期的另一部分——
更新
1. 根据相关改变预处理数据
当组件已经被初始化后组件调用者修改组件的属性
时,组件的componentWillReceiveProps()
方法会被调用,在这里,你可以对外部传入的数据进行一些预处理
,比如从props中读取数据写入state
。
2.判断是否必须更新,过滤无效渲染
默认情况下,组件调用者修改组件属性时,React会遍历
这个组件的所有子组件,进行“灌水”,将props从上到下一层一层传下去,并逐个执行更新操作,虽然React内部已经进行过很多的优化,这个过程是很快的,如果你追求极致性能或者你发现这个过程花费了太久时间,使用shouldComponentUpdate()
——
有时候,props发生了变化,但组件和子组件并不会因为这个props的变化而发生变化,打个比方,你有一个表单组件,你想要修改表单的name,同时你能够确信这个name不会对组件的渲染产生任何影响
,那么你可以直接在这个方法里return false来终止后续行为。这样就能够避免无效的虚拟DOM对比
了,对性能会有明显提升。
如果这个时候有同学仍然饥渴难耐,那么你可以尝试 不可变数据结构(用过mongodb的同学应该懂)。
3.更新的准备工作
组件在更新前,React会执行componentWillUpdate()方法,这个方法类似于前面看到的componentWillMount()方法,唯一不同的地方只是这个方法在执行的时候组件是已经渲染过的。需要注意的是,不可以在这个方法中修改props或state,如果要修改,应当在componentWillReceiveProps()中修改
。
4.对比虚拟DOM并替换
然后是渲染,React会拿这次返回的虚拟DOM和缓存中的虚拟DOM进行对比
,找出【最小修改点】,然后替换。
5.更新完成后
React会调用组件的componentDidUpdate方法,这个方法类似于前面的componentDidMount方法,你仍然可以在这里可以通过this.getDOMNode()方法取得最终的DOM节点。