首页
题库
公司真题
专项练习
面试题库
在线编程
面试
面试经验
AI 模拟面试
简历
求职
学习
基础学习课
实战项目课
求职辅导课
专栏&文章
竞赛
搜索
我要招人
发布职位
发布职位、邀约牛人
更多企业解决方案
AI面试、笔试、校招、雇品
HR免费试用AI面试
最新面试提效必备
登录
/
注册
牛客477642835号
门头沟学院 Web前端
发布于浙江
关注
已关注
取消关注
@来个offer吧!!!!:
React常见面试题汇总
众所周知,React是目前互联网大厂使用最多的前端框架,在面试过程中,面试官也更喜欢有React开发经验的同学。本文总结了React中一些重要的特性,同时也是在平时的面试中经常被问到的一些问题。希望对各位前端开发同学有所帮助,如果觉得还不错请多多点赞收藏。 目录 如何理解 Rect React与Vue的异同 如何理解虚拟 DOM React 生命周期 React 状态复用的方式 如何理解 React Hooks React Diff 算法 React fiber 架构的理解 react 性能优化的手段 setState 是同步的还是异步的 React 合成事件 如何理解 Rect react 是什么? react 是一个用于构建用户界面的 javascript 库。 为什么会出现 react 这样的框架 在我们早期的前端开发中,我们通过 JavaScript 来手动操作 DOM 以达到和用户交互的目的,但是原生的 DOM 操作繁琐并且还会存在兼容性问题。因此在我们前端开发中出现 jquery 这样的框架,来帮助我们简化 DOM 操作,同时解决了各种兼容性问题。但是随着我们的项目变得越来越复杂,我们发现,光有 DOM 操作远远不够,我们还要有应用结构,因此我们开始探讨前端组件化的问题,通过组件化的方式来让我们的项目结构变得更加清晰,同时也引入了 MVX 的概念。接着大家发现 MVX 的数据绑定依然需要我们手动监听 model 的变化,然后去做各种 DOM 操作,数据到视图层的映射依然繁琐。于是大家就开始推崇 MVVM 的数据绑定,于是就出现了例如 Angular,React 和 Vue 这样的前端框架。 react 的特点 react具有声明式,组件化以及一次学习,随处编写的特点,因此 react 特别适合用于构建快速响应的大型 web 应用 React与Vue的异同 相同点: 使用虚拟 DOM 提供响应式和组件化的视图组件 将注意力集中保持在核心库,而将其他功能如路由、全局状态管理交给相关的库 不同点: 视图更新 在react中,当某个组件的状态发生变化的时候,会以该组件为根,重新渲染整个组件树,如果要避免不必要的子组件重渲染,我们需要在所有可能的地方使用 PureComponent 或者是 shouldComponentUpdate 方法。 在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以vue能精确知晓哪个组件确实需要被重渲染。Vue的特点可以让开发者不再考虑此类优化,从而更好地专注于应用本身 HTML 和 CSS 在 react 中,everything is JavaScript,不仅是 html 可以用 jsx 表示,连 css 也有 js 的解决方案。 Vue 的整体思想是拥抱经典的 Web 技术,并在其上进行扩展。使用 html,css 和 js 来构建模板。 在这个方面我觉得 vue 是在适应开发者,而 react 想要改变开发者。 同时,在组件作用域内的 css 上,react 是使用的 css-in-js 的解决方案或者是 css modules。而 vue 使用 scoped 来控制 css 规模 vue 的路由管理和状态管理由官方维护,而 react 则是把这些问题交给社区,创建了一个更为分散的生态系统,因此react的生态系统相对于 vue 更加繁荣。 原生渲染 由于两者都是使用的虚拟 dom 技术,因此都可以构建原生的安卓或者 ios 应用,例如 react-native 和 weex 如何理解虚拟 DOM 虚拟 dom 是什么 虚拟 DOM 是对 DOM 的抽象,本质上是 JavaScript 对象 为什么需要虚拟dom 首先,我们知道在前端性能优化中,有一个很重要的一项就是尽可能少的操作 DOM,不仅仅是 DOM 操作相对较慢,更是因为频繁的 DOM 操作会造成浏览器的回流或者重绘,这些都会对我们的性能造成影响。因此我们需要一个抽象,在patch过程中,尽量一次将差异更新到 DOM 中。 其次,现代前端框架的一个基本要求就是无须手动操作DOM,这样可以大大提高开发效率。 最后,虚拟DOM可以更好地实现跨平台,用于编写原生应用。 React 生命周期 React < 16.3 组件的生命周期包含挂载或者更新组件过程中被触发的一系列方法。这些方法可以在组件渲染UI之前或者之后触发。以下是 React 16.3 之前的生命周期 挂载生命周期 constructor(props):初始化 props 和 State。 componentWillMount(): 一旦属性被获取并且也初始化了 State,该方法将会被触发。该方法是在 DOM 被渲染之前触发的,并且可以用来初始化第三方脚本库、启动动画、请求数据,以及其他可能需要在组件被渲染之前执行的额外步骤。还可以在该方法中触发 setState 方法,在组件被初次渲染之前修改组件的 State。 在组件被渲染完毕之前调用 setState 方法将不会启动更新生命周期。在组件渲染完毕之后调用 setState 方法就会启动更新生命周期。 如果用户在 componentWillMount 方法中定义的回调函数内调用了 setState 方法,那么它将会在组件被渲染完成之后被触发,并且会启动更新生命周期。 render():只要父组件 render 被调用,其所有子组件的 render 都会被调用 componentDidMount():组件被渲染完毕之后触发,可以获取到 DOM。 componentWillUnmount():组件被卸载之前触发,在这里可以清除一些后台进程。 更新生命周期 更新生命周期是当组件 State 发生变化或者从父组件接收到新的属性时触发的一系列方法。 更新生命周期会在每次调用 setState 方法后启动。调用 setState 方法过程内部的更新生命周期将会引发无限递归循环。因此只能在 componentWillReceiveProps 方法内部调用 setState 方法,它允许组件属性被更新后更新 State。 更新生命周期包括以下几个方法: componentWillReceiveProps(nextProps): 仅当新的属性被传递给了组件后才会调用。这也是唯一可以调用 setState 方法的地方。 shouldComponentUpdate(nextProps, nextState): 更新生命周期的门卫,一个可以取消更新操作的谓词。该方法可以通过只允许执行必须的更新操作来改进性能。 componentWillUpdate(nextProps, nextState): 只在组件更新之前触发。和 componentWillMount 类似,只是它会在每次更新操作之前被触发。 componentDidUpdate(prevProps, prevState): 只在更新操作发生后,调用 render 方法之后触发。类似 componentDidMount 方法,不过它会在每次更新之后触发。 React >= 16.4 React 大于等于 16.4 的生命周期图谱如下: 还有一些不常用的生命周期钩子: 这里我们着重介绍 getDerivedStateFromProps生命周期。需要注意的是,React 16.3 的版本中 getDerivedStateFromProps 的触发范围和 16.4^ 是不同的,主要区别在 setState 和 forceUpdate 时会不会触发。具体可以看生命周期图。 该生命周期的使用场景主要有两个: 无条件的根据 prop 来更新内部 state,也就是只要有传入 prop 值,就更新 state。 只有 props 值和 state 不同时才更新 state。 具体示例可以参考官方文档。 React 状态复用的方式 mixin mixin之间的相互依赖会形成依赖链,当我们改动其中一个mixin的状态的时候,很可能会直接影响其他的mixin,不利于代码维护 不同mixin的之间可能会产生命名冲突 增加组件的复杂性,当我们引入的mixin较多时,会让代码的逻辑变得十分复杂,难以维护。 高阶组件 HOC需要在原组件上进行包裹或者嵌套,如果大量使用HOC,将会产生非常多的嵌套,这让调试变得非常困难。 render props render props是一项通过props来告知组件需要渲染什么内容的技术,它的使用场景是什么呢? 很多时候我们渲染一个组件,但是它的逻辑和数据却依赖于父组件,这种情况下我们可以把那部分可以复用的逻辑抽取在父组件中,并且在父组件暴露一个参数 render 来接收渲染子组件的方法,并且通过这个方法把子组件所依赖的数据传给它,这种方式就是render props。 render props的使用思路是控制反转,子组件通过render props的方式定义好渲染自身的函数,父组件再把子组件需要的数据传给这个函数,子组件拿到数据后可以随意的渲染自身。 hooks 减少状态逻辑复用的风险,mixin引入的状态逻辑会相互覆盖,HOC也可能会出现 props 覆盖 避免层级嵌套,让组件更易于理解 使用函数代替 class ,更符合 react 函数式理念 问题 只能在顶层使用 hooks 只在 React 函数中使用 hooks 如何理解 React Hooks 是什么 hook 是 react16.8 的新增特性,它可以让你在不编写 class 的情况下使用 state 以及其他的 react 特性 解决了什么问题 react解决了我们在使用和维护 react 中经常遇到的问题 组件之间的状态和逻辑复用 以前使用 render props 和 高阶组件。但是这类方案需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解。 复杂组件变得难以理解 我们经常维护一些组件,组件起初很简单,但是逐渐会被状态逻辑和副作用充斥。每个生命周期常常包含一些不相关的逻辑。例如,组件常常在 componentDidMount 和 componentDidUpdate 中获取数据。但是,同一个 componentDidMount 中可能也包含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount 中清除。相互关联且需要对照修改的代码被进行了拆分,而完全不相关的代码却在同一个方法中组合在一起。如此很容易产生 bug,并且导致逻辑不一致。 难以理解的 class class 组件中经常需要手动去绑定 this,因此需要我们去理解 js 中 this 的工作原理,增加了学习成本 有哪些 useState useEffect useRef useContext useMemo useCallback React Diff 算法 React的 diff 策略: 在 Web UI 中,跨层级移动节点的操作很少,可以忽略不计 拥有相同类的两个组件会生成相似的树形结构,拥有不同类的两个组件会生成不同的树形结构 对于同一层级的一组子节点,可以通过唯一 id 进行区分 基于以上策略,React 分别对 Tree diff、Component diff 以及 Element diff 进行了优化。 tree dif 在 tree diff 的时候,react 只会对两颗树的同一层级的节点进行比较,即同一个父节点下的所有子节点。当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。这样只需要对树进行一次遍历,便能完成整个 DOM 树的比较。 如果出现了跨层级的移动,React会删掉该节点以及其所有的子节点。然后在新的节点下创建节点。 如下图,A 节点(包括其子节点)整个被移动到 D 节点下,由于 React 只会简单的考虑同层级节点的位置变换,而对于不同层级的节点,只有创建和删除操作。当根节点发现子节点中 A 消失了,就会直接销毁 A;当 D 发现多了一个子节点 A,则会创建新的 A(包括子节点)作为其子节点。此时,React diff 的执行情况:create A -> create B -> create C -> delete A。 只有删除、创建操作,没有移动操作 component diff React 是基于组件构建的应用,因此在进行 diff 时,react 遵循以下策略: 如果是同一类型的组件,则按照原策略继续比较 DOM tree 如果是不同类型的组件,react 会替换整个组件下的所有子节点 对于同一类型的组件,其虚拟dom可能并没有发生变化,因此react提供shouldComponentUpdate来让我们判断该组件是否需要diff。 如下图,当 component D 改变为 component G 时,即使这两个 component 结构相似,一旦 React 判断 D 和 G 是不同类型的组件,就不会比较二者的结构,而是直接删除 component D,重新创建 component G 以及其子节点。 element diff 当节点处于同一层级的时候,react diff 提供了三种节点操作,移动、删除、插入。 当节点没有 key 的时候,在对比新老虚拟DOM的时候,会出现频繁的创建,删除节点的操作,不能很好的做到节点复用,影响 diff 的效率。 因此我们在对同一层级的子元素进行比较的时候,需要添加唯一的key进行区分。 有了 key 之后,react diff 在同层级比较的时候, 首先会初始化 lastIndex 和 nextIndex,两者都为 0. 遍历新的虚拟dom集合,找到新的集合中的每个节点在老集合中的位置 oldIndex, 如果 oldIndex >= lastIndex,则该节点保持不动,并更新 lastIndex = Math.max(lastIndex, oldIndex),然后更新该节点的位置为 nextIndex,nextIndex ++ 如果 oldIndex < lastIndex,则移动该节点至 nextIndex 的位置,同时更新 lastIndex = Math.max(lastIndex, oldIndex),nextIndex ++ 如果老集合中没有找到节点,说明节点是新增的,则会创建新节点插入到 nextIndex 的位置 当完成新集合中所有节点 diff 时,最后还需要对老集合进行遍历,判断是否存在新集合中没有但老集合中仍存在的节点,发现存在这样的节点 D,因此删除节点 D,到此 diff 全部完成。 当然,React diff 还是存在些许不足与待优化的地方,如下图所示,若新集合的节点更新为:D、A、B、C,与老集合对比只有 D 节点移动,而 A、B、C 仍然保持原有的顺序,理论上 diff 应该只需对 D 执行移动操作,然而由于 D 在老集合的位置是最大的,导致其他节点的 _mountIndex < lastIndex,造成 D 没有执行移动操作,而是 A、B、C 全部移动到 D 节点后面的现象。 优化 react diff 算法 例如以下两个新旧数组,React的算***把 a, b, c 移动到他们的相应的位置 + 1共三步操作,而inferno.js则是直接将d移动到最前端这一步操作.其中一个核心的思想就是利用LIS(最长递增子序列)的思想做动态规划,找到最小的移动次数. * A: [a b c d] * B: [d a b c] React fiber 架构的理解 fiber 之前的 react存在的问题: 由于 js 引擎和页面渲染引擎两个线程是互斥的,当其中一个线程执行的时候,另一个线程只能挂起等待。 如果 js 线程长时间占用了主线程,那么我们渲染层面的更新就不得不长时间的等待,界面长时间不更新,会导致页面响应变慢,用户可能会感觉卡顿。 这也正是 react15 所面临的问题,当 react 在渲染组件时,从开始到渲染完成整个过程是一气呵成的,无法中断。 如果组件较大,那么 js 线程会一直执行,然后等到整棵 vDOM 树计算完成后,才会交给渲染线程,这就有可能出现卡顿的现象。 因此 facebook 提出了 react fiber架构 fiber 把渲染更新过程拆分为多个子任务,其中优先级高的先执行,并且每次只做其中的一小部分,做在完成一部分任务之后,将控制权交回给浏览器,让浏览器有时间进行页面的渲染。等浏览器忙完之后有剩余时间,再继续之前 React 未完成的任务,是一种合作式调度。 上述实现的方式是window.requestIdleCallback() 方法,该方法在浏览器空闲时段内调用排队的函数 会导致多次调用某些生命周期钩子 react把更新分为两个阶段 reconciliation 这个阶段的更新是可以被打断的,主要涉及的生命周期: componentWillMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate commit 这个阶段的更新是不能被打断的 componentDidUpdate componentDidMount componentWillUnmount react 性能优化的手段 避免不必要的 render,主要是使用 shouldComponentUpdate 和 PureComponent 或者 Reac.memo 实现,pureComponent 只做浅层比较,因此可以使用 immutable 的方式进行更新 使用 useMemo 或 useCallback 缓存变量或者函数 使用 Suspense 或者 lazy 进行组件的懒加载 import React, { Suspense } from 'react';const OtherComponent = React.lazy(() => import('./OtherComponent'));function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div> );} setState 是同步的还是异步的 主要取决于 react 当前是否处于 批量更新的模式,如果是,则会把更新存在一个队列里面,如果不是,则会直接执行此次更新。 setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。 setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。 setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。 React 合成事件 React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象。React 的合成事件它并不是绑定在 DOM 元素本身,而是统一绑定在 document 上。这样做主要有三个目的 进行浏览器兼容,实现更好的跨平台 事件对象可能会被频繁创建和回收,使用事件池来进行统一管理,达到性能优化的目的 合成事件与原生事件的执行顺序:先执行原生事件,再处理 React 合成事件 合成事件与原生事件的区别 命名方式不同 事件处理函数写法不同 阻止默认行为方式不同
点赞 25
评论 3
全部评论
推荐
最新
楼层
暂无评论,快来抢首评~
相关推荐
01-22 13:12
已编辑
美团_测试开发
第一次被同事气笑了
原本说好的一起合作,结果在第二天就要产出结果的时候发现对方负责的部分一点都没做,然后你是这个项目的主要负责人,出了问题你背锅,你会怎么做?事情缘由因为我是做测试的平时需要测试一些需求,对于一些大的需求可能需要测试一两周,但是互联网公司需要的是快速交付,很难说服产品你测试需要花这么久。这里可以简单给大家介绍一下,互联网之所以加班内卷严重很重要的一个因素就是需要快速的迭代产品,快速的抢占市场,积累用户往往是比你慢慢研发打磨细节要更好。比如A公司花了半年做出来一个产品,然后上线虽然接收到一些差评但是抢占了大量的市场后续慢慢优化这些差评,B公司花了一两年做和A公司同样的产品,虽然有些功能比A更好但是人...
烤点老白薯:
同事做的对 主要负责人是你凭啥让我干 想给我派活儿 让领导转达
你最近因为什么迷茫?
点赞
评论
收藏
分享
01-27 12:00
门头沟学院 C++
充满鲜花的世界到底在哪里
抛开那些所谓的“大厂光环”和“核心赛道”不谈,我真正的梦中情司其实很简单,无非就是把“钱多事少”贯彻到底。在这个赛博许愿池里,我真心祈祷能拥有一份朝九晚五的安稳,双休是雷打不动的底线,从来不知加班为何物,更没有那些让人半夜惊醒的绩效考核和KPI压力。我希望工资卡里的数字能轻松撑起我的诗和远方,年假多到需要做攻略去消磨,公司的Outing不是换个地方换种形式的军训,而是真真切切的环球旅行。我不求改变世界,只求在这个疯狂内卷的时代里,能拥有一方没有压力的天地,这种神仙日子,哪怕是让我探大财起大厝驶豪车娶水某我也愿意,求求了把这样的神仙Offer狠狠砸向我吧!
抛开难度不谈,你最想去哪...
点赞
评论
收藏
分享
01-15 12:26
西南民族大学 Java
根本找不到实习 !甚至打了招呼都不回 而且还是没发简历的情况下
点赞
评论
收藏
分享
2025-12-19 15:04
门头沟学院 Java
逗一逗小HR
小肥罗:
hr爱上你了,你负责吗哈哈
点赞
评论
收藏
分享
01-27 16:00
TP-LINK_通信算法工程师(准入职员工)
tp-link内推,tp-link内推码
TPLINK普联面经2024.6.11一面(35分钟)1.介绍项目2.项目中你负责了什么问的比较浅,介绍了就过了2024.6.14二面(40分钟)1.介绍项目2.你有什么创新点3.遇到的困难4.(针对项目的细节)5.DC-DC和LDO各自的优劣点:DC-DC有哪些类型6.什么是1dB压缩点7.什么是三阶交调失真8.四层板设计注意什么9.HFSS的操作步骤(项目拷打,问的非常细)10.保研排名2024.6.19三面(22分钟)1賃鋇槛檸鎿墜惬煩ẩ腼绍项目2.创新点和不足3.如果重新做一遍,你有哪些改进4.你的优势是什么,不足是什么5.保研成绩6.参加过的竞赛7.拿到的奖学金TP-LINK普联20...
点赞
评论
收藏
分享
评论
点赞成功,聊一聊 >
点赞
收藏
分享
评论
提到的真题
返回内容
全站热榜
更多
1
...
J人永远闲不下来于是去提前实习
2622
2
...
mentor视角下的优秀实习生
2332
3
...
大厂提前实习对AI开发的新感悟
2332
4
...
拥抱AI,程序员的最后出路
2167
5
...
牛客吐槽大会 | 有槽不吐,留着过年?吐完领现金红包,痛快!
1922
6
...
努力挣钱的意义具象化了
1773
7
...
真正会被取代的,是你心里面的幻觉
1756
8
...
去独角兽做龙头还是去大厂做凤尾
1543
9
...
我身材再曼妙,也没有我的工资好笑!
1469
10
...
滴滴lastweek,知无不言
1387
创作者周榜
更多
正在热议
更多
#
牛客吐槽大会
#
3259次浏览
69人参与
#
机械人你知道哪些单休企业
#
83130次浏览
415人参与
#
今年春招是金一银二嘛?
#
8838次浏览
119人参与
#
参加完秋招的机械人,还参加春招吗?
#
103777次浏览
686人参与
#
1月小结:你过的开心吗?
#
2011次浏览
52人参与
#
抛开难度不谈,你最想去哪家公司?
#
4820次浏览
118人参与
#
为什么有人零实习也能进大厂?
#
5431次浏览
132人参与
#
AI求职实录
#
4044次浏览
112人参与
#
AI时代的工作 VS 传统时代的工作,有哪些不同?
#
8695次浏览
207人参与
#
机械人春招想让哪家公司来捞你?
#
379333次浏览
3141人参与
#
当你问AI“你会取代我的工作吗”,它说_?
#
3960次浏览
141人参与
#
你的第一家实习公司是什么档次?
#
4476次浏览
75人参与
#
没关系,至少我的__很曼妙
#
3833次浏览
65人参与
#
赚钱的意义在这一刻具象化
#
4155次浏览
99人参与
#
你的landing期是如何度过的?
#
8997次浏览
176人参与
#
除了Java,最推荐学什么技术?
#
6185次浏览
151人参与
#
我发现了面试通关密码
#
1600190次浏览
19679人参与
#
一人一道大厂面试题
#
114127次浏览
1263人参与
#
你觉得什么岗位会被AI替代
#
36887次浏览
256人参与
#
你在职场上见过哪些“水货”同事
#
30778次浏览
168人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务