JSX
<b style=""><font color="#ffffff">JSX是什么-What</font></b>
JavaScript 的一种<b>语法扩展</b>,类似模板语言,但是它<b>具备 JavaScript 的能力(</b>提供了完全的 JavaScript 表达式支持<b>)<br></b><b><br></b>
在JSX中使用JavaScript的表达式
JavaScript表达式是什么
JSX 本身就是表达式
在 props 中使用表达式
使用`...`语法
表达式作为 children
本质
React.createElement(component, props, ...children) 函数的语法糖
<b><font color="rgba(0, 0, 0, 0)">为什么需要 JSX</font>-<font color="#c41230">Why/优点</font></b>
JSX 代码层次分明、嵌套关系清晰,简洁直观
允许开发者使用类似 HTML 标签的语法来<b>创建虚拟 DOM</b>
降低学习成本,提升研发效率与研发体验
<b><font color="#c41230">How</font></b>
JSX 语法是如何在 JavaScript 中生效的
<b>Babel</b> 将JSX 标签转化成 React.createElement()
Babel
JSX 是如何映射为 DOM 的
JSX 被转换为 React.createElement(type,config,...children)
作用:创建虚拟DOM
参数
<b>type:</b>用于标识节点的类型
<b>config</b>:组件所有的属性-props
<b>children</b>:所有的子节点”“子元素”
大概执行逻辑
依次对 ref、key、self 和 source 属性赋值
把 config 里面的属性都一个一个挪到 props 这个之前声明好的对象里面
把子元素放入 props.children中
处理 defaultProps
最后返回ReactElement方法,并传入刚才处理过的参数
React.createElement 执行后返回 React.Element(虚拟 DOM)
对传入的参数进行组装,最后返回一个 element(是一个JS对象,即<b>虚拟 DOM</b> 中的一个节点)
最后调用 ReactDOM.render(element,container) 转换为真实 DOM
参数
<b>element</b>: 需要渲染的元素(ReactElement)
<b>container</b>: 元素挂载的目标容器(一个真实DOM)
作用: 将虚拟DOM插入的真实DOM中
约定
自定义组件以大写字母开头
React 认为小写的 tag 是原生 DOM 节点,如 `div`
JSX 标记可以直接使用属性语法, 如 `<mentu.Item>`
生命周期
只有组件自己时的执行顺序
存在子组件时的执行顺序
React16 <b>class 组件</b>的生命周期
挂载阶段
constructor
是什么
一个组件的构造函数,组件更新到界面上之前会先调用`constructor`
特点
用于初始化内部状态,很少使用
唯一可以直接修改 state 的地方
getDerivedStateFromProps
是干什么的-what
替换 componentWillReceiveProps
有且仅有一个核心用途:使用 <b><font color="#c41230">props 来派生/更新 state</font></b>
如何使用-how
getDerivedStateFromProps 是一个静态方法
参数
props(自父组件的 props )
state(当前组件自身的 state)
返回值必须是对象或者 null
Why
为什么是一个静态/static 方法
静态方法不依赖组件实例而存在,因此这个方法内部是访问不到 this 的
意义
<ul><li>确保生命周期函数的行为更加可控可预测,</li><li>从根源上帮开发者避免不合理的编程方式,</li><li>避免生命周期的滥用;</li></ul>
为 Fiber 架构铺路
<b><font color="#c41230">注意事项</font></b>
getDerivedStateFromProps, componentWillReceiveProps<br>一些滥用场景及其后果
特点
尽量不要使用,维护 state/props 状态一致性会增加复杂度
每次 render 都会调用
组件内的 render
组件必须定义的一个生命周期方法,用来描述 DOM 结构
componentDidMount
特点
UI 渲染完成后调用
只执行一次
典型场景:获取外部资源
更新阶段
getDerivedStateFromProps
shouldComponentUpdate
是什么
告诉组件是否需要重新渲染,用于性能优化,比如判定指定 props 发生改变,组件才进行重新渲染
特点
决定虚拟 DOM 是否需要重绘
一般可以由 `PureComponent`自动实现
典型场景:性能优化
组件内的 render
getSnapshotBeforeUpdate
特点
在最近一次渲染输出(提交到 DOM 节点)之前调用,state 已更新
getSnapshotBeforeUpdate 与 componentDidUpdate 配合使用
典型场景:捕获 render 之前的 DOM 状态
例如:捕获滚动条位置
componentDidUpdate
特点
每次 UI 更新时被调用
典型场景:页面需要根据 props 变化重新获取数据
卸载阶段
componentWillUnmount
是什么
当组件从页面上消失时,需要进行销毁的时候被调用
<b><font color="#c41230">废弃的生命周期</font></b>
有哪些
componentWillMount
componentWillUpdate
componentWillReceiveProps
为什么废弃
确保了 Fiber 机制下数据和视图的安全性,
确保了生命周期方法的行为更加纯粹、可控、可预测
Fiber架构
从 Fiber架构 的角度理解生命周期,对生命周期的影响
Render 阶段(<font color="#c41230"><b>纯净且不包含副作用。可能会被 React 暂停,中止或重新启动</b></font>)
相比 React16.4之前的变更
在 render 阶段,一个庞大的更新任务被分解为了一个个的工作单元,<br>这些工作单元有着不同的优先级,React 可以根据优先级的高低去实现工作单元的打断和恢复<br><br>工作单元(也就是任务)的重启将会伴随着对部分生命周期的重复执行,<br>为了<font color="#c41230">避免开发者对生命周期的滥用,就废弃了几个生命周期</font><br>
componentWillMount
componentWillUpdate
componentWillReceiveProps
内容
constructor
getDerivedStateFromProps
shouldComponentUpdate
组件内的 render
Pre-commit 阶段(<b><font color="#c41230">可以读取 DOM</font></b>)
getSnapshotBeforeUpdate
Commit 阶段(<b><font color="#c41230">可以使用 DOM,运行副作用,安排更新</font></b>)
componentDidMount
componentDidUpdate
componentWillUnmount
什么是Fiber思想-what
Fiber 会将一个大的更新任务拆解为许多个小任务
每当执行完一个小任务时,渲染线程都会把主线程交回去,看看有没有优先级更高的工作要处理
处理完其他更高优先级任务后,再次回来处理之前的任务
Why(Fiber出现的原因)
Stack Reconciler的问题
栈调和是一个同步的递归过程,本质是树的深度优先遍历的过程<br><br>当处理结构相对复杂、体量相对庞大的虚拟 DOM 树时,Stack Reconciler 需要的调和时间会很长,<br>这就意味着 JavaScript 线程将长时间地霸占主线程,<br>进而导致我们上文中所描述的渲染卡顿/卡死、交互长时间无响应等问题<br>
How
原理?
Diff算法
React15版本
Stack Reconciler(栈调和)
原始diff思路(算法复杂度O(n^3) )
循环递归进行树节点的一一对比
diff算法O (n) 复杂度的思路
当根节点为不同类型的元素时,React 会拆卸原有的树并且建立起新的树
作用: 减少 Diff 过程中冗余的递归操作
当对比两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性
列表形式的子元素比较:
how
React 引入了 key 属性。当子元素拥有 key 时,<br>React 使用 key 来匹配原有树上的子元素以及最新树上的子元素
key 充当每个节点的 ID(唯一标识)
作用
栈调和机制下的 Diff 算法,其实是树的深度优先遍历的过程。而树的深度优先遍历,总是和递归有关
问题
同步执行任务;<br>无法中断任务;<br>无法将任务拆分为多个小任务;
React16版本
Fiber Reconciler(Fiber 调和)
setState
常见案例
在钩子函数中setSate拿不到最新值
在合成事件中执行多个同样的setSate,最终只会执行一次,并且也拿不到最新值
在setTimeout/setInterval 中设置setState,可以拿到最新的值
在原生DOM事件中设置setState,可以拿到最新的值
源码流程-原理-How
流程
将新的 state 放进组件的状态队列里
用 enqueueUpdate 来处理将要更新的实例对象
源码流程??????
setState
enqueueSetState
将state push 到异步队列
enqueueUpdate
batchingStrategy
isBatchingUpdates(是否处于更新阶段)
是
batchedUpdates(更新state)
transaction(事务)
数据传递方式/组件通信方式
props
场景
父-子组件通信
子-父组件通信
兄弟组件通信
为什么不推荐用 props 解决其他场景的需求
如:多层组件嵌套的场景
中间组件会引入很多不属于自己的属性
增加代码量,造成代码冗余,开发与维护成本高
生产者-消费者模式 Context API
如何使用
解决了什么问题
发布-订阅模式
优点: 监听事件的位置和触发事件的位置不受限制
Redux