React组件&props
React
编写组件主要是有两种方式:函数组件和class
组件。一般声明组件的时候都会申明为首字母大写。
定义组件最简单的方式就是编写JavaScript
函数:
1 | function Welcome(props) { |
还可以使用ES6
的 class
来定义组件:
1 | class Welcome extends React.Component { |
注意有一点:React
是一个直接操作数据的声名式框架,它不会直接操作DOM
,它是通过虚拟DOM
来实现最后的渲染的,会帮我们节约掉大量操作DOM
的代码。
子组件和父组件的通信方式
父组件想传递信息到子组件是利用props
,state
属性来实现
子组件想传递给父组件信息的话是通过调用父组件传递给子组件的方法间接的传递信息
子组件和父组件之间通信是单向数据流
这个也就是为什么组件无论是使用函数声明还是通过class
声明,都决不能修改自身的props
。因为这个属性是父组件传递给子组件的。这是为了保证当数据出现错误的时候能很容易的找到出错的地方在哪。
React虚拟DOM
在React
中,render
执行的结果得到的并不是真正的DOM
节点,结果仅仅是轻量级的JavaScript
对象,我们称之为virtual DOM
。 虚拟DOM
是React
的一大亮点,具有batching
(批处理)和高效的Diff
算法。
这个批处理优化基于:setState
是异步的,当多个变化很相近的时候就放到一起来去生成虚拟DOM
。
它也是使得跨端应用得到实现的重要原因。
React修改数据之后的流程
state
数据JSX
模板- 数据+模板生成虚拟
DOM
(损耗了性能):['div',{id: 'abc'},'hello world!']
- 用虚拟DOM的结构生成真实DOM来显示:
<div id='abc'>'hello world!'</div>
state
发生改变- 数据+模板生成新的虚拟
DOM
- 比较原始虚拟
DOM
和新的虚拟DOM
的区别 - 直接操作
DOM
,更改内容
JSX
模板变成真实DOM
的过程:JSX
-> React.createElement
-> js
对象 -> 真实的DOM
。
DIFF算法
两个树的完全的diff
算法是一个时间复杂度为 O(n3)
的问题。 但是在前端中,你会很少跨层地移动DOM
元素,所以真实的DOM
算法会对同一个层级的元素进行对比。
div
只会和同一层级的div
对比,第二层级的只会和第二层级对比。 这样算法复杂度就可以达到O(n)
.
利用深度优先遍历,记录差异然后把差异引用到真正的DOM
树上。
React的生命周期函数
React的生命周期分为三个阶段:
- 挂载阶段
- 更新阶段
- 卸载阶段
constructor(组件构造函数)
如果没有显示定义它,我们会拥有一个默认的构造函数。在构造函数里面我们一般会做两件事:
- 初始化
state
对象 - 给自定义方法绑定
this
render
React
中最核心的方法,一个组件中必须要有这个方法
返回的类型有以下几种:
- 原生的
DOM
,如div
React
组件Fragment
(片段)Portals
(插槽)- 字符串和数字,被渲染成
text
节点 Boolean
和null
,不会渲染任何东西
componentDidMount
组件装载之后调用,此时我们可以获取到DOM节点并操作,,比如对canvas
,svg
的操作,服务器请求,订阅都可以写在这个里面,但是记得在componentWillUnmount
中取消订阅
shouldComponentUpdate
函数原型shouldComponentUpdate(nextProps, nextState)
,有两个参数nextProps
和nextState
,表示新的属性和变化之后的state
,返回一个布尔值,true
表示会触发重新渲染,false
表示不会触发重新渲染,默认返回true
。
componentDidUpdate
组件改变之后调用,有三个参数prevProps
,prevState
,snapshot
,表示之前的props
,之前的state
,和snapshot
。第三个参数是getSnapshotBeforeUpdate
返回的。在这个函数里我们可以操作DOM
,和发起服务器请求,还可以setState
,但是注意一定要用if语句控制,否则会导致无限循环
componentWillUnmount
当我们的组件被卸载或者销毁了就会调用,我们可以在这个函数里去清除一些定时器,取消网络请求,清理无效的DOM
元素等垃圾清理工作
注意不要在这个函数里去调用setState
,因为组件不会重新渲染了。
之前还有componentWillMount()
和componentDidMount()
是组件即将被渲染到页面之前触发和组件已经被渲染到页面中后触发,这个在现在的版本已经被去除了。使用HOOK
能很方便的代替生命周期函数。