你真的了解 React 吗?我们在面试中往往涉及 React 时,第一个问题就是“解释 React 是什么”。解释一种技术是什么,在面试中也是非常常见的引起 话题的题目。本篇文章我就带你掌握这一类概念题的解答技巧。
官方的解释:React 是一个 UI 库,它的核心思想是UI=F(data)
, 即界面的呈现是由函数传入的参数决定的
开发者不再需要关心界面时如何渲染的,只要关心数据的生成和传递,这大大提高的开发者的开发效率,节省了开发时间
其次 React 设计的
JSX
语法来描述视图虚拟DOM
修改真实DOM
setState
修改数据生命周期
阶段做不同的事事件委托
的方式来捕获 DOM 事件等特性进一步简化的 真实 DOM 操作的复杂性
虚拟DOM
真实DOM
就是我们在浏览器开发者工具中看到的DOM
结构虚拟DOM
简单来说就是 JS 对象,此对象中的字段包含了对真实DOM
的描述:type
:是什么标签/元素props
:标签/元素有哪些属性children
:是否有子元素a
当 DOM
操作(渲染更新)比较频繁时,
React 底层会先将前后两次的虚拟DOM
树进行对比,
定位出具体需要更新的部分,生成一个补丁集
,
最后只把“补丁”打在需要更新的那部分真实DOM
上,实现精准的“差量更新”。
如果当虚拟 DOM 的构建和diff
的过程相对复杂(比如很多递归遍历等操作),那么虚拟 DOM 的 JS 计算是比较耗时的
Diff算法
一般的原始 diff 思路算法复杂度是O(n^3)
,即循环递归进行树节点的一一对比
但 React 的 diff 算法
是 O (n)
复杂度的思路
当对比两棵虚拟 DOM 树时,React 首先比较两棵树的根节点。不同类型的根节点元素会有不同的形态
当对比两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性。
Diff
过程中冗余的递归操作key 属性
。当子元素拥有 key
时,React 使用 key
来匹配原有树上的子元素以及最新树上的子元素,如果 key
不同 不同则会拆卸原有的 key
节点并且建立起新的 key
节点详细内容请参考React 官方文档- Diffing 算法[2]
image.png
constructor()
:组件的构造函数,组件更新到界面上之前会先调用state
的地方2 . static getDerivedStateFromProps(nextProps, prevState)
:用于从外部的属性去初始化一些内部的状态
state
需要从 props
初始化时使用state/props
状态一致性会增加复杂度render
都会调用3 . render()
::组件必须定义的一个生命周期方法,用来描述 虚拟 DOM 结构
4 . componentDidMount()
: 用于数据请求,定义一些外部资源等等副作用
static getDerivedStateFromProps(nextProps, prevState)
shouldComponentUpdate(nextProps, nextState)
:告诉组件是否需要重新渲染,用于性能优化,比如判定指定 props 发生改变,组件才进行重新渲染PureComponent
自动实现3 . render()
4 . getSnapshotBeforeUpdate(prevProps, prevState)
componentDidUpdate
搭配使用render
之前的 DOM 状态5 . componentDidUpdate(prevProps, prevState)
props
变化重新获取数据componentWillUnmount()
: 做些资源释放,卸载副作用的事情详细内容请参考React 知识体系之生命周期及使用场景[3]
state
用于组件内部数据传递,state
数据可以通过this.setSate
或者useState
进行修改
props
用于组件外部组件数据传递,props
不能直接修改.主要使用场景是:
兄弟组件通信
父子组件通信
"爷孙组件"
组件通信
props
的使用范围虽然更加广泛,但也有其局限性:对于嵌套层次较深的组件,如果使用props
传递数据,会导致代码冗余,增加数据传递的复杂度
在 JavaScript 中,super 指的是父类构造函数。(在我们的示例中,它指向 React.Component 实现。)
在调用父类的构造函数之前,你是不能在 constructor
中使用 this
关键字的。JavaScript 不允许这个行为
class Checkbox extends React.Component {
constructor(props) {
// 还不能使用 `this`
super(props);
// ✅ 现在可以了
this.state = { isOn: true };
}
// ...
}
复制代码
为什么一定要传递 props
呢?为了让 React.Component
构造函数能够初始化 this.props
React 内部代码:
// React 內部
class Component {
constructor(props) {
this.props = props;
// ...
}
}
复制代码
实例代码:
class Button extends React.Component {
constructor(props) {
super(); // ? We forgot to pass props
console.log(props); // ✅ {}
console.log(this.props); // ? undefined
}
// ...
}
复制代码
class Button extends React.Component {
constructor(props) {
super(props); // ✅ We passed props
console.log(props); // ✅ {}
console.log(this.props); // ✅ {}
}
// ...
}
复制代码
有了 Hooks 以后,我们几乎就不需要 super
和 this
了
详细内容请参考为什么我们要写 super(props) ?[4]
setState
setSate
拿不到最新值setSate
,最终只会执行一次,并且也拿不到最新值原因:
setState
就会触发一次 re-render
(重渲染)re-ernder
,setState
被设计成异步的形式setState
,就把它塞进一个队列里“攒起来”。等时机成熟,再把“攒起来”的 state
结果做合并(对于相同属性的设置,React 只会为其保留最后一次的更新),最后只针对最新的 state
值走一次更新流程。这个过程,叫作**批量更新
**setTimeout/setInterval
、原生 DOM
中的 setStatesetTimeout/setInterval
中设置 setState
,可以拿到最新的值原生 DOM
事件中设置 setState
,可以拿到最新的值原因:
setState
的“异步”并不是说内部由异步代码实现,其实源码本身执行的过程和代码都是同步的,
只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”
setState
的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和 setTimeout
中不会批量更新
详细内容请参考setState 到底是同步的,还是异步的?[5]
React事件机制
React 中的事件叫合成事件
:React 底层使用事件委托
的方式对真实 DOM 事件进行了封装,使合成事件具有更好的浏览器兼容性和性能
当事件在具体的 DOM 节点上被触发后,最终都会冒泡到 document 上,document 上所绑定的统一事件处理程序会将事件分发到具体的组件实例
合成事件是 React 自定义的事件对象,它符合 W3C 规范,在底层抹平了不同浏览器的差异,在上层面向开发者暴露统一的、稳定的、与 DOM 原生事件相同的事件接口。
开发者们由此便不必再关注烦琐的兼容性问题,可以专注于业务逻辑的开发。
e.nativeEvent
属性获取到它ref
API 进行获取详细内容请参考React 事件与 DOM 事件有何不同?[6]
这种方式在组件每次 render 渲染的时候,都会重新进行 bind 的操作,影响性能
class App extends React.Component {
handleClick() {
console.log("this > ", this);
}
render() {
return <div onClick={this.handleClick.bind(this)}>test</div>;
}
}
复制代码
通过 ES6 的上下文来将 this 的指向绑定给当前组件,同样在每一次 render 的时候都会生成新的方法,影响性能
class App extends React.Component {
handleClick() {
console.log("this > ", this);
}
render() {
return <div onClick={(e) => this.handleClick(e)}>test</div>;
}
}
复制代码
在 constructor 中预先 bind 当前组件,可以避免在 render 操作中重复绑定
class App extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log("this > ", this);
}
render() {
return <div onClick={this.handleClick}>test</div>;
}
}
复制代码
能够避免在 render 操作中重复绑定
class App extends React.Component {
constructor(props) {
super(props);
}
handleClick = () => {
console.log("this > ", this);
};
render() {
return <div onClick={this.handleClick}>test</div>;
}
}
复制代码
函数组件没有实例,因此没有this
const App = () => {
handleClick = (e) => {
console.log(e);
};
return <div onClick={this.handleClick}>test</div>;
};
复制代码
详细内容请参考React 构建组件的方式有哪些[7]
render props
Hooks
组件Hooks
详细内容请参考React 构建组件的方式有哪些[8]
单个组件内部数据传递
state
父组件向子组件传递
props
子组件向父组件传递
props
兄弟组件之间的通信
props
父组件向后代组件传递
props
Context API
Redux
发布-订阅模式
EventBus
非关系组件传递
Context API
Redux
发布-订阅模式
EventBus
说到 React 的 key,就要说到 React 的 Diff 算法
详细内容请参考React 列表循环为什么需要 key[9]
参考资料
[1]https://juejin.cn/post/6978685539985653767: https://juejin.cn/post/6978685539985653767
[2]https://zh-hans.reactjs.org/docs/reconciliation.html#the-diffing-algorithm: https://link.juejin.cn?target=https%3A%2F%2Fzh-hans.reactjs.org%2Fdocs%2Freconciliation.html%23the-diffing-algorithm
[3]https://juejin.cn/post/6981739846461030408: https://juejin.cn/post/6981739846461030408
[4]https://overreacted.io/zh-hans/why-do-we-write-super-props/: https://link.juejin.cn?target=https%3A%2F%2Foverreacted.io%2Fzh-hans%2Fwhy-do-we-write-super-props%2F
[5]https://www.yuque.com/u221766/xgl0mb/oxl3ik: https://link.juejin.cn?target=https%3A%2F%2Fwww.yuque.com%2Fu221766%2Fxgl0mb%2Foxl3ik
[6]https://www.yuque.com/u221766/xgl0mb/iu68y0: https://link.juejin.cn?target=https%3A%2F%2Fwww.yuque.com%2Fu221766%2Fxgl0mb%2Fiu68y0
[7]https://juejin.cn/post/6952907248393781284#heading-2: https://juejin.cn/post/6952907248393781284#heading-2
[8]https://juejin.cn/post/6952907248393781284: https://juejin.cn/post/6952907248393781284
[9]https://juejin.cn/post/6940974776441634823: https://juejin.cn/post/6940974776441634823
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/QxS6dCVN0L7tMdKbCYrDhQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。