我的React知识体系
2021-06-28 22:59:10 237 举报
AI智能生成
我掌握了React的核心概念,包括组件化、虚拟DOM和单向数据流。我能熟练使用JSX语法编写组件,并了解生命周期方法的使用场景。我还熟悉状态管理和路由管理工具,如Redux和React Router。此外,我对Hooks有一定的了解,能够使用useState、useEffect等Hooks优化代码。在性能优化方面,我了解shouldComponentUpdate和React.memo的使用。我还具备跨浏览器兼容性问题的处理能力,并能使用Webpack等构建工具进行项目配置。总之,我在React开发方面具备扎实的基础知识和实践经验。
作者其他创作
大纲/内容
MVVM是什么
JSX
JSX是什么-What
JavaScript 的一种语法扩展,类似模板语言,但是它具备 JavaScript 的能力(提供了完全的 JavaScript 表达式支持)
在JSX中使用JavaScript的表达式
JavaScript表达式是什么
JSX 本身就是表达式
在 props 中使用表达式
使用`...`语法
表达式作为 children
本质
React.createElement(component, props, ...children) 函数的语法糖
为什么需要 JSX-Why/优点
JSX 代码层次分明、嵌套关系清晰,简洁直观
允许开发者使用类似 HTML 标签的语法来创建虚拟 DOM
降低学习成本,提升研发效率与研发体验
How
JSX 语法是如何在 JavaScript 中生效的
Babel 将JSX 标签转化成 React.createElement()
Babel
JSX 是如何映射为 DOM 的
JSX 被转换为 React.createElement(type,config,...children)
作用:创建虚拟DOM
参数
type:用于标识节点的类型
config:组件所有的属性-props
children:所有的子节点”“子元素”
大概执行逻辑
依次对 ref、key、self 和 source 属性赋值
把 config 里面的属性都一个一个挪到 props 这个之前声明好的对象里面
把子元素放入 props.children中
处理 defaultProps
最后返回ReactElement方法,并传入刚才处理过的参数
React.createElement 执行后返回 React.Element(虚拟 DOM)
对传入的参数进行组装,最后返回一个 element(是一个JS对象,即虚拟 DOM 中的一个节点)
最后调用 ReactDOM.render(element,container) 转换为真实 DOM
参数
element: 需要渲染的元素(ReactElement)
container: 元素挂载的目标容器(一个真实DOM)
作用: 将虚拟DOM插入的真实DOM中
约定
自定义组件以大写字母开头
React 认为小写的 tag 是原生 DOM 节点,如 `div`
JSX 标记可以直接使用属性语法, 如 `<mentu.Item>`
生命周期
只有组件自己时的执行顺序
存在子组件时的执行顺序
React16 class 组件的生命周期
挂载阶段
constructor
是什么
一个组件的构造函数,组件更新到界面上之前会先调用`constructor`
特点
用于初始化内部状态,很少使用
唯一可以直接修改 state 的地方
getDerivedStateFromProps
是干什么的-what
替换 componentWillReceiveProps
有且仅有一个核心用途:使用 props 来派生/更新 state
如何使用-how
getDerivedStateFromProps 是一个静态方法
参数
props(自父组件的 props )
state(当前组件自身的 state)
返回值必须是对象或者 null
Why
为什么是一个静态/static 方法
静态方法不依赖组件实例而存在,因此这个方法内部是访问不到 this 的
意义
- 确保生命周期函数的行为更加可控可预测,
- 从根源上帮开发者避免不合理的编程方式,
- 避免生命周期的滥用;
为 Fiber 架构铺路
注意事项
getDerivedStateFromProps, componentWillReceiveProps
一些滥用场景及其后果
一些滥用场景及其后果
特点
尽量不要使用,维护 state/props 状态一致性会增加复杂度
每次 render 都会调用
组件内的 render
组件必须定义的一个生命周期方法,用来描述 DOM 结构
componentDidMount
是什么
用于数据请求,定义一些外部资源等等副作用
特点
UI 渲染完成后调用
只执行一次
典型场景:获取外部资源
更新阶段
getDerivedStateFromProps
shouldComponentUpdate
是什么
告诉组件是否需要重新渲染,用于性能优化,比如判定指定 props 发生改变,组件才进行重新渲染
特点
决定虚拟 DOM 是否需要重绘
一般可以由 `PureComponent`自动实现
典型场景:性能优化
组件内的 render
getSnapshotBeforeUpdate
特点
在最近一次渲染输出(提交到 DOM 节点)之前调用,state 已更新
getSnapshotBeforeUpdate 与 componentDidUpdate 配合使用
典型场景:捕获 render 之前的 DOM 状态
例如:捕获滚动条位置
componentDidUpdate
特点
每次 UI 更新时被调用
典型场景:页面需要根据 props 变化重新获取数据
卸载阶段
componentWillUnmount
是什么
当组件从页面上消失时,需要进行销毁的时候被调用
特点
做些资源释放,卸载副作用的事情
废弃的生命周期
有哪些
componentWillMount
componentWillUpdate
componentWillReceiveProps
为什么废弃
确保了 Fiber 机制下数据和视图的安全性,
确保了生命周期方法的行为更加纯粹、可控、可预测
Fiber架构
从 Fiber架构 的角度理解生命周期,对生命周期的影响
Render 阶段(纯净且不包含副作用。可能会被 React 暂停,中止或重新启动)
相比 React16.4之前的变更
在 render 阶段,一个庞大的更新任务被分解为了一个个的工作单元,
这些工作单元有着不同的优先级,React 可以根据优先级的高低去实现工作单元的打断和恢复
工作单元(也就是任务)的重启将会伴随着对部分生命周期的重复执行,
为了避免开发者对生命周期的滥用,就废弃了几个生命周期
这些工作单元有着不同的优先级,React 可以根据优先级的高低去实现工作单元的打断和恢复
工作单元(也就是任务)的重启将会伴随着对部分生命周期的重复执行,
为了避免开发者对生命周期的滥用,就废弃了几个生命周期
componentWillMount
componentWillUpdate
componentWillReceiveProps
内容
constructor
getDerivedStateFromProps
shouldComponentUpdate
组件内的 render
Pre-commit 阶段(可以读取 DOM)
getSnapshotBeforeUpdate
Commit 阶段(可以使用 DOM,运行副作用,安排更新)
componentDidMount
componentDidUpdate
componentWillUnmount
什么是Fiber思想-what
Fiber 会将一个大的更新任务拆解为许多个小任务
每当执行完一个小任务时,渲染线程都会把主线程交回去,看看有没有优先级更高的工作要处理
处理完其他更高优先级任务后,再次回来处理之前的任务
特点
可中断
可恢复
优先级
Why(Fiber出现的原因)
Stack Reconciler的问题
栈调和是一个同步的递归过程,本质是树的深度优先遍历的过程
当处理结构相对复杂、体量相对庞大的虚拟 DOM 树时,Stack Reconciler 需要的调和时间会很长,
这就意味着 JavaScript 线程将长时间地霸占主线程,
进而导致我们上文中所描述的渲染卡顿/卡死、交互长时间无响应等问题
当处理结构相对复杂、体量相对庞大的虚拟 DOM 树时,Stack Reconciler 需要的调和时间会很长,
这就意味着 JavaScript 线程将长时间地霸占主线程,
进而导致我们上文中所描述的渲染卡顿/卡死、交互长时间无响应等问题
How
ReactDOM.render
初始化阶段
原理?
理解Virtual DOM及key属性的作用
优点
原理
代码实现
虚拟DOM
what
概念
描述真实DOM 的JS对象
组成
type
props
children
how
挂载阶段
JSX转为React.createElement(type,config,...children),然后构建出虚拟 DOM 树
ReactDOM.render 将虚拟 DOM 转为真实 DOM
更新阶段
页面的变化在作用于真实 DOM 之前,会先作用于虚拟 DOM,
虚拟 DOM 将在 JS 层借助算法先对比出具体有哪些真实 DOM 需要被改变,
然后再将这些改变作用于真实 DOM
虚拟 DOM 将在 JS 层借助算法先对比出具体有哪些真实 DOM 需要被改变,
然后再将这些改变作用于真实 DOM
why
前置知识
DOM 操作解决方案的发展历程
原生 JS 支配下的“人肉 DOM” 时期
解放生产力的先导阶段:jQuery 时期
优点
jQuery 首先解决的就是“API 不好使”这个问题——它将 DOM API 封装为了相对简单和优雅的形式,同时一口气做掉了跨浏览器的兼容工作,并且提供了链式 API 调用、插件扩展等一系列能力用于进一步解放生产力
问题
满足不了日益膨胀的 DOM 操作需求
早期模板引擎方案
优点
解决烦琐 DOM 操作的问题
how
读取 HTML 模板并解析它,分离出其中的 JS 信息
将解析出的内容拼接成字符串,动态生成 JS 代码
运行动态生成的 JS 代码,吐出“目标 HTML
将“目标 HTML”赋值给 innerHTML,触发渲染流水线,完成真实 DOM 的渲染
问题
更新 DOM 的方式是将已经渲染出 DOM 整体注销后再整体重渲染,
并且不存在更新缓冲这一说。
在 DOM 操作频繁的场景下,模板引擎可能会直接导致页面卡死
并且不存在更新缓冲这一说。
在 DOM 操作频繁的场景下,模板引擎可能会直接导致页面卡死
虚拟 DOM
作用
当 DOM 操作(渲染更新)比较频繁时,它会先将前后两次的虚拟 DOM 树进行对比,定位出具体需要更新的部分,生成一个“补丁集”,最后只把“补丁”打在需要更新的那部分真实 DOM 上,实现精准的“差量更新”
优点
能够在提供更爽、更高效的研发模式(也就是函数式的 UI 编程方式)的同时,仍然保持一个还不错的性能。
误解
操作虚拟DOM不一定比操作真实DOM快,不一定性能更好
虚拟 DOM 的劣势主要在于 JS 计算的耗时(虚拟 DOM 的构建和 diff 过程逻辑则相对复杂,它不可避免地涉及递归、遍历等耗时操作),
而 DOM 操作的能耗和 JS 计算的能耗根本不在一个量级
而 DOM 操作的能耗和 JS 计算的能耗根本不在一个量级
虚拟 DOM 解决的关键问题有两个
研发体验/研发效率的问题
提升一定性能
不直接操作DOM,数据驱动视图
跨平台的问题
虚拟 DOM,它描述的东西可以是
真实 DOM,
iOS 界面、
安卓界面、小程序......同一套虚拟 DOM,
可以对接不同平台的渲染逻辑,从而实现“一次编码,多端运行”
真实 DOM,
iOS 界面、
安卓界面、小程序......同一套虚拟 DOM,
可以对接不同平台的渲染逻辑,从而实现“一次编码,多端运行”
Diff算法
React15版本
Stack Reconciler(栈调和)
原始diff思路(算法复杂度O(n^3) )
循环递归进行树节点的一一对比
diff算法O (n) 复杂度的思路
当根节点为不同类型的元素时,React 会拆卸原有的树并且建立起新的树
作用: 减少 Diff 过程中冗余的递归操作
当对比两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性
列表形式的子元素比较:
how
React 引入了 key 属性。当子元素拥有 key 时,
React 使用 key 来匹配原有树上的子元素以及最新树上的子元素
React 使用 key 来匹配原有树上的子元素以及最新树上的子元素
key 充当每个节点的 ID(唯一标识)
作用
key的赋值规则是什么
唯一
稳定
栈调和机制下的 Diff 算法,其实是树的深度优先遍历的过程。而树的深度优先遍历,总是和递归有关
问题
同步执行任务;
无法中断任务;
无法将任务拆分为多个小任务;
无法中断任务;
无法将任务拆分为多个小任务;
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(事务)
React事件机制
前置知识
原生DOM的事件机制
流程
事件捕获阶段
目标阶段
事件冒泡阶段
性能问题
界面渲染出1000个ul>li元素,如果为每一个li元素都添加点击事件,可能造成严重的性能问题
性能问题优化
事件委托
What
把多个子元素的同一类型的监听逻辑,合并到父元素上通过一个监听函数来管理的行为,就是事件委托
Why
通过事件委托,我们可以减少内存开销、简化注册步骤,大大提高开发效率
原理
对于这 1000 个 li 来说,无论点击动作发生在哪个 li 上,点击事件最终都会被冒泡到它们共同的父亲——ul 元素上去,
所以我们完全可以让 ul 来帮忙感知这个点击事件
所以我们完全可以让 ul 来帮忙感知这个点击事件
如何做
合成事件
是什么
合成事件是 React 自定义的事件对象
原理
当事件在具体的 DOM 节点上被触发后,最终都会冒泡到 document 上,
document 上所绑定的统一事件处理程序会将事件分发到具体的组件实例
document 上所绑定的统一事件处理程序会将事件分发到具体的组件实例
源码解析............
Why
合成事件是 React 自定义的事件对象,它符合W3C规范,
在底层抹平了不同浏览器的差异,在上层面向开发者暴露统一的、稳定的、与 DOM 原生事件相同的事件接口。
开发者们由此便不必再关注烦琐的兼容性问题,可以专注于业务逻辑的开发。
在底层抹平了不同浏览器的差异,在上层面向开发者暴露统一的、稳定的、与 DOM 原生事件相同的事件接口。
开发者们由此便不必再关注烦琐的兼容性问题,可以专注于业务逻辑的开发。
对 React 来说,事件委托主要的作用应该在于帮助 React 实现了对所有事件的中心化管控
How
如何获取原生事件
虽然合成事件并不是原生 DOM 事件,但它保存了原生 DOM 事件的引用。
当你需要访问原生 DOM 事件对象时,可以通过合成事件对象的 e.nativeEvent 属性获取到它
当你需要访问原生 DOM 事件对象时,可以通过合成事件对象的 e.nativeEvent 属性获取到它
如何获取原生/真实DOM
ref
Where
React常见事件
onClick
组件设计模式
类组件
问题
高阶组件
代码实现
使用场景
问题
render props
纯函数组件
Hooks组件
优点
自定义Hooks
数据传递方式/组件通信方式
props
场景
父-子组件通信
子-父组件通信
兄弟组件通信
为什么不推荐用 props 解决其他场景的需求
如:多层组件嵌套的场景
中间组件会引入很多不属于自己的属性
增加代码量,造成代码冗余,开发与维护成本高
生产者-消费者模式 Context API
如何使用
解决了什么问题
发布-订阅模式
优点: 监听事件的位置和触发事件的位置不受限制
Redux
生态圈
Redux
是什么
为什么/优点
特点/特性
单一数据源-store
可预测性-action
纯函数更新 Store-reducer
理解API
中间件
原理
常见库
redux saga
redux thunk
redux log
React Router
是什么
为什么/优点
特点
基本原理
场景
页面跳转
路由传递参数
嵌套路由
根据路由确定当前菜单的点击状态
Fetch
与Ajax,Axios的比较优缺点是什么
封装
Next.js
UI组件库
Antd
单元测试工具
Jest
Enzyme
开发调试工具
ESLint
Prettier
React DevTool
Redux DevTool
Chrome DevTool
React常见场景的最佳实践
React中手写拖放的实现
基于路由实现菜单导航
根据路由确定当前菜单的点击状态
集成第三方JS库图表库
使用React Portals实现对话框
常见页面布局的手写实现
使用React Router管理登录和授权
页面数据需要来源多个请求的处理
详情页面的加载与缓存
于React Router实现分步操作
将步骤条的当前切换状态存储到URL中
性能优化
性能分析工具
React DevTool
Chrome DevTool
怎么做
按需加载
webpack的 import API
React Layze load
使用较新的React版本
React组件性能优化
使用 shouldComponentUpdate 规避冗余的更新逻辑
PureComponent + Immutable.js
React.memo 与 useMemo
前端通用
资源加载过程中的优化、减少重绘与回流、服务端渲染、启用 CDN
经验
组件卸载后不能再setState
循环遍历子节点时需要给每一个子节点加上key属性
原因
0 条评论
下一页