虚拟 DOM 的两种创建方式
1  | //1、jsx创建  | 
虚拟 DOM
关于虚拟 DOM:
- 本质是 Object 类型的对象(一般对象)
 - 虚拟 DOM 比较“轻”,真实 DOM 比较“重”,因为虚拟 DOM 是 React 内部在用,无需真实 DOM 上那么多的属性。
 - 虚拟 DOM 最终会被 React 转化为真实 DOM,呈现在页面上。
 
JSX 语法规则
- 定义虚拟 DOM 时,不要写引号。
 -  标签中混入 JS 表达式时要用
{}。 - 样式的类名指定不要用 class,要用 className。
 -  内联样式,要用
style={{key:value}}的形式去写。 - 只有一个根标签
 - 标签必须闭合
 - 标签首字母
(1).若小写字母开头,则将该标签转为 html 中同名元素,若 html 中无该标签对应的同名元素,则报错。
(2).若大写字母开头,react 就去渲染对应的组件,若组件没有定义,则报错。 
一定注意区分:【js 语句(代码)】与【js 表达式】
(1). 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
下面这些都是表达式:
1  | a;  | 
(2). 语句(代码):
下面这些都是语句(代码):
1  | if(){}  | 
模块与组件、模块化与组件化的理解
1、模块
- 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件
 - 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
 - 作用:复用 js, 简化 js 的编写, 提高 js 运行效率
 
2、组件
- 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image 等等)
 - 为什么要用组件: 一个界面的功能更复杂
 - 作用:复用编码, 简化项目编码, 提高运行效率
 
3、模块化
当应用的 js 都以模块来编写的, 这个应用就是一个模块化的应用
4、组件化
当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
ES6 类回顾
- 类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写。
 - 如果 A 类继承了 B 类,且 A 类中写了构造器,那么 A 类构造器中的 super 是必须要调用的。
 - 类中所定义的方法,都放在了类的原型对象上,供实例去使用。
 
1  | //创建一个Person类  | 
函数式和类式组件
1  | //1.创建函数式组件  | 
执行了ReactDOM.render(<MyComponent/>.......)之后,发生了什么?
- React 解析组件标签,找到了 MyComponent 组件。
 - 发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用到原型上的 render 方法。
 - 将 render 返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中。
 
类方法中的 this 指向
1  | class Person {  | 
类中的方法默认是开启了局部的严格模式,所以 this 会指向
undefined
组件实例三大属性
1、state
- state 是组件对象最重要的属性, 值是对象(可以包含多个 key-value 的组合)
 - 组件被称为”状态机”, 通过更新组件的 state 来更新对应的页面显示(重新渲染组件)
 
1  | class Weather extends React.Component {  | 
类组件简写形式
1  | class Weather extends React.Component {  | 
2、props
props 基本使用
1  | class Person extends React.Component {  | 
对 props 进行限制
1  | //引入prop-types 用于对组件标签属性进行限制  | 
props 的简写
1  | class Person extends React.Component {  | 
扩展属性: 将对象的所有属性通过 props 传递
1  | /*  | 
3、refs
字符串形式的 ref
1  | class Demo extends React.Component {  | 
回调函数形式的 ref
1  | class Demo extends React.Component {  | 
回调 ref 回调指向次数问题
关于回调 refs 的说明
如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的
1  | class Demo extends React.Component {  | 
createRef 的使用React.createRef调用后可以返回一个容器,该容器可以存储被 ref 所标识的节点,该容器是“专人专用”的
1  | class Demo extends React.Component {  | 
事件处理
(1).通过 onXxx 属性指定事件处理函数(注意大小写)
a.React 使用的是自定义(合成)事件, 而不是使用的原生 DOM 事件 —————— 为了更好的兼容性
b.React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效
(2).通过 event.target 得到发生事件的 DOM 元素对象 ——————————不要过度使用 ref(发生事件的元素正好是 ref 绑定的元素,可以使用 event)
收集表单数据
1、非受控组件
1  | class Login extends React.Component {  | 
2、受控组件
1  | //创建组件  | 
生命周期
旧生命周期
- 初始化阶段: 由 ReactDOM.render()触发—初次渲染
 - constructor()
 - componentWillMount()
 - render()
 - componentDidMount() =====> 常用
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息 - 更新阶段: 由组件内部 this.setSate()或父组件 render 触发
 - shouldComponentUpdate()
 - componentWillUpdate()
 - render() =====> 必须使用的一个
 - componentDidUpdate()
强制更新:forceUpdate() -> 不更改任何状态中的数据,强制更新一下 -》 不受阀门控制 - 卸载组件: 由 ReactDOM.unmountComponentAtNode()触发
 - componentWillUnmount() =====> 常用
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息 

1  | //...  | 
新生命周期
- 初始化阶段: 由 ReactDOM.render()触发—初次渲染
 - constructor()
 - getDerivedStateFromProps
 - render()
 - componentDidMount() =====> 常用
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息 - 更新阶段: 由组件内部 this.setSate()或父组件重新 render 触发
 - getDerivedStateFromProps
 - shouldComponentUpdate()
 - render()
 - getSnapshotBeforeUpdate
 - componentDidUpdate()
 - 卸载组件: 由 ReactDOM.unmountComponentAtNode()触发
 - componentWillUnmount() =====> 常用
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息 

1  | //...  | 
DOM 的 diffing 算法
1  | /*  |