Jack N @ GitHub

Full stack engineer, focus on: Angular/React, node.js/.Net

0%

2021 React 面试题汇总

1. React 基本问题

1.1. React有什么特点

  1. 它使用虚拟DOM而不是真正的DOM。
  2. 它可以用服务器端渲染。
  3. 它遵循单向数据流或数据绑定。

1.2. React的主要优点。

  1. 它提高了应用的性能
  2. 可以方便地在客户端和服务器端使用
  3. 由于 JSX,代码的可读性很好
  4. React 很容易与 Meteor,Angular 等其他框架集成
  5. 使用React,编写UI测试用例变得非常容易

1.3. React有哪些限制

  1. React 只是一个库,而不是一个完整的框架
  2. 它的库非常庞大,需要时间来理解
  3. 新手程序员可能很难理解
  4. 编码变得复杂,因为它使用内联模板和 JSX

1.4. Virtual DOM 的工作原理。

Virtual DOM 是一个轻量级的 JavaScript 对象,它最初只是 real DOM 的副本。它是一个节点树,它将元素、它们的属性和内容作为对象及其属性。 React 的渲染函数从 React 组件中创建一个节点树。然后它响应数据模型中的变化来更新该树,该变化是由用户或系统完成的各种动作引起的。

Virtual DOM 工作过程有三个简单的步骤。

  1. 每当底层数据发生改变时,整个 UI 都将在 Virtual DOM 描述中重新渲染。
  2. 然后计算之前 DOM 表示与新表示的之间的差异。
  3. 完成计算后,将只用实际更改的内容更新 real DOM。

1.5. react diff 原理

  1. 把树形结构按照层级分解,只比较同级元素。
  2. 给列表结构的每个单元添加唯一的 key 属性,方便比较。
  3. React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
    合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
  4. 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。

1.6. React 项目用过什么脚手架

creat-react-app, Yeoman, umi 等

1.7. 如果进行三次setState会发生什么,循环执行setState组件会一直重新渲染吗

setState这个方法是用来告诉react组件数据有更新,有可能需要重新渲染。它是异步的,react通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能,所以进行三次只有一次的效果,并不会导致多次渲染。

此外再使用setState改变状态之后,立刻使用this.state去拿最新的状态往往是拿不到的,如果需要最新的state做业务的话,可以在componentDidUpdate或者setState的回调函数里获取。

1.8. 调用 setState 之后发生了什么?

在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

1.9. 什么是JSX

JSX 是JavaScript XML 的简写。是 React 使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的模板语法。这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能。

1.10. 浏览器是否可以直接读取读取JSX?

浏览器只能处理 JavaScript 对象,而不能读取常规 JavaScript 对象中的 JSX。所以为了使浏览器能够读取 JSX,首先,需要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给浏览器。

1.11. vue和react适用的场景

  • vue适合webapp,适合做用户交互多,各种动态效果变化丰富的应用。特别是PC、手机的网页版,商城等页面。因为vue实现逻辑复杂的功能比较简单。
  • react适合oa系统,适合大批量的数据展示、适合做大型应用。特别适合公司的后台管理系统。因为react对那种比较复杂的交互,实现起来比较麻烦,没有vue方便。同时react的渲染原理是渲染整个组件树,所以,一方面是费性能,而且代码写起来逻辑复杂。但是react对批量数据操作很厉害。
  • 总而言之,项目要求比较高的适合使用react,因为react的社区更活跃一些,尤其是各种UI框架比较稳定、系统,可以信赖。Vue的社区也很活跃,但相对而言各种组件五花八门,大多数不够完善,缺乏系统性和迭代性,对于项目的后期维护和新手入手都不太友好。
  • 从应用上来看,react打出来的包会大一些,相对来说,vue的包小一些,如果项目场景对加载速度由要求,建议使用vue。

2. React 组件

2.1. 为什么说在React中,一切都是组件

组件是 React 应用 UI 的构建块。这些组件将整个 UI 分成小的独立并可重用的部分。每个组件彼此独立,而不会影响 UI 的其余部分。

2.2. React 中 render() 的目的。

每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form>、<group>、<div> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。

2.3. React组件生命周期的阶段是什么?

React 组件的生命周期有三个不同的阶段:

  1. 初始渲染阶段:这是组件即将开始其生命之旅并进入 DOM 的阶段。
  2. 更新阶段:一旦组件被添加到 DOM,它只有在 prop 或状态发生变化时才可能更新和重新渲染。这些只发生在这个阶段。
  3. 卸载阶段:这是组件生命周期的最后阶段,组件被销毁并从 DOM 中删除。

2.4. react 生命周期函数

  1. 挂载
    当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:
  • constructor()
  • getDerivedStateFromProps(): 当从父类接收到 props 并且在调用另一个渲染器之前调用。
  • render()
  • componentDidMount(): 仅在第一次渲染后在客户端执行。
  1. 更新
    当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
  • getDerivedStateFromProps(): 当从父类接收到 props 并且在调用另一个渲染器之前调用。
  • shouldComponentUpdate(): 根据特定条件返回 true 或 false。如果你希望更新组件,请返回true 否则返回 false。默认情况下,它返回 false。
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate(): 在渲染发生后立即调用
  1. 卸载
    当组件从 DOM 中移除时会调用如下方法:
  • componentWillUnmount(): 从 DOM 卸载组件后调用。用于清理内存空间。

2.5. 在生命周期中的哪一步你应该发起 AJAX 请求?

我们应当将AJAX 请求放到 componentDidMount 函数中执行,主要原因有下:

React 下一代调和算法 Fiber 会通过开始或停止渲染的方式优化应用性能,其会影响到 componentWillMount 的触发次数。对于 componentWillMount 这个生命周期函数的调用次数会变得不确定,React 可能会多次频繁调用 componentWillMount。如果我们将 AJAX 请求放到 componentWillMount 函数中,那么显而易见其会被触发多次,自然也就不是好的选择。 (新版本的React,已经拿掉了)

如果我们将 AJAX 请求放置在生命周期的其他函数中,我们并不能保证请求仅在组件挂载完毕后才会要求响应。如果我们的数据请求在组件挂载之前就完成,并且调用了setState函数将数据添加到组件状态中,对于未挂载的组件则会报错。而在 componentDidMount 函数中进行 AJAX 请求则能有效避免这个问题。

2.6. 展示组件(Presentational component)和容器组件(Container component)之间有何不同

  • 展示组件关心组件看起来是什么。展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。
  • 容器组件则更关心组件是如何运作的。容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions,并将其作为回调提供给展示组件。容器组件经常是有状态的,因为它们是(其它组件的)数据源。

2.7. 调用 super(props) 的目的是什么

在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。

传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props。

2.8. 除了在构造函数中绑定 this,还有其它方式吗

你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-react-app 也是默认支持的。

在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。

2.9. 什么是 Props?

Props 是 React 中属性的简写。它们是只读组件,必须保持纯,即不可变。它们总是在整个应用中从父组件传递到子组件。子组件永远不能将 prop 送回父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据。

2.10. 什么是状态(State)?

状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state 访问它们。

2.11. 类组件(Class component)和函数式组件(Functional component)之间有何不同

  • 类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问 store 并维持状态 (React v16.8以后,可以使用hook使用state和部分生命周期钩子函数)
  • 当组件仅是接收 props,并将组件自身渲染到页面时,该组件就是一个 ‘无状态组件(stateless component)’,可以使用一个纯函数来创建这样的组件。这种组件也被称为哑组件(dumb components)或展示组件

2.12. 如何更新组件的状态?

  1. 可以用 this.setState()更新组件的状态
  2. 更新时,可以只更新部分属性,保留其他属性值

##React 中的箭头函数有什么作用
箭头函数(=>)是用于编写函数表达式的简短语法。这些函数允许正确绑定组件的上下文(不改变this),因为在 ES6 中默认下不能使用自动绑定。使用高阶函数时,箭头函数非常有用。

2.13. React中的事件是什么?

在 React 中,事件是对鼠标悬停、鼠标单击、按键等特定操作的触发反应。处理这些事件类似于处理 DOM 元素中的事件。但是有一些语法差异,如:

  1. 用驼峰命名法对事件命名而不是仅使用小写字母。
  2. 事件作为函数而不是字符串传递。

事件参数重包含一组特定于事件的属性。每个事件类型都包含自己的属性和行为,只能通过其事件处理程序访问。

2.14. React中的合成事件是什么?

合成事件是围绕浏览器原生事件充当跨浏览器包装器的对象。它们将不同浏览器的行为合并为一个 API。这样做是为了确保事件在不同浏览器中显示一致的属性。

2.15. 何为受控组件(controlled component)

在 HTML 中,类似 <input>, <textarea> 和 <select> 这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时,如 onChange 会更新 state,重新渲染组件。一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为”受控元素”。

2.16. React 的 refs 有什么作用?

Refs 是 React 中引用的简写。它是一个有助于存储对特定的 React 元素或组件的引用的属性,它将由组件渲染配置函数返回。用于对 render() 返回的特定元素或组件的引用。当需要进行 DOM 测量或向组件添加方法时,它们会派上用场。

2.17. 列出一些应该使用 Refs 的情况

  • 需要管理焦点、选择文本或媒体播放时
  • 触发式动画
  • 与第三方 DOM 库集成

2.18. shouldComponentUpdate 是做什么的,(react 性能优化是哪个周期函数?)

shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘 dom。因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。

2.19. 什么是高阶组件(HOC - higher order component)?

高阶组件是重用组件逻辑的高级方法,是一种源于 React 的组件模式。 HOC 是自定义组件,在它之内包含另一个组件。它们可以接受子组件提供的任何动态,但不会修改或复制其输入组件中的任何行为。你可以认为 HOC 是“纯(Pure)”组件。

2.20. 你能用HOC做什么?

  • 代码重用,逻辑和引导抽象
  • 渲染劫持
  • 状态抽象和控制
  • Props 控制

2.21. 什么是纯组件(Pure Component)?

纯(Pure) 组件是可以编写的最简单、最快的组件。它们可以替换任何只有 render() 的组件。这些组件增强了代码的简单性和应用的性能。

2.22. React 中 key 的重要性是什么?

key 用于识别唯一的 Virtual DOM 元素及其驱动 UI 的相应数据。它们通过回收 DOM 中当前所有的元素来帮助 React 优化渲染。这些 key 必须是唯一的数字或字符串,React 只是重新排序元素而不是重新渲染它们。这可以提高应用程序的性能。

3. Redux

3.1. 什么是Flux

Flux 是一种强制单向数据流的架构模式。它控制派生数据,并使用具有所有数据权限的中心 store 实现多个组件之间的通信。整个应用中的数据更新必须只能在此处进行。 Flux 为应用提供稳定性并减少运行时的错误。

3.2. 什么是Redux?

Redux 是当今最热门的前端开发库之一。它是 JavaScript 程序的可预测状态容器,用于整个应用的状态管理。使用 Redux 开发的应用易于测试,可以在不同环境中运行,并显示一致的行为。

3.3. Redux遵循的三个原则是什么?

  1. 单一事实来源:整个应用的状态存储在单个 store 中的对象/状态树里。单一状态树可以更容易地跟踪随时间的变化,并调试或检查应用程序。
  2. 状态是只读的:改变状态的唯一方法是去触发一个动作。动作是描述变化的普通 JS 对象。就像 state 是数据的最小表示一样,该操作是对数据更改的最小表示。
  3. 使用纯函数进行更改:为了指定状态树如何通过操作进行转换,你需要纯函数。纯函数是那些返回值仅取决于其参数值的函数。

3.4. “单一事实来源”有什么理解?

Redux 使用 “Store” 将程序的整个状态存储在同一个地方。因此所有组件的状态都存储在 Store 中,并且它们从 Store 本身接收更新。单一状态树可以更容易地跟踪随时间的变化,并调试或检查程序。

3.5. 列出 Redux 的组件

  • Action – 这是一个用来描述发生了什么事情的对象。React 中的 Action 必须具有 type 属性,该属性指示正在执行的 ACTION 的类型。必须将它们定义为字符串常量,并且还可以向其添加更多的属性。在 Redux 中,action 被名为 Action Creators 的函数所创建。
  • Reducer – 这是一个确定状态将如何变化的地方。Reducers 是纯函数,它规定应用程序的状态怎样因响应 ACTION 而改变。Reducers 通过接受先前的状态和 action 来工作,然后它返回一个新的状态。它根据操作的类型确定需要执行哪种更新,然后返回新的值。如果不需要完成任务,它会返回原来的状态。
  • Store – 整个程序的状态/对象树保存在Store中。 Store 是一个 JavaScript 对象,它可以保存程序的状态,并提供一些方法来访问状态、调度操作和注册侦听器。
  • View – 只显示 Store 提供的数据。

3.6. Redux与Flux的区别

Flex Redux
Store 包含状态和更改逻辑 Store 和更改逻辑是分开的
有多个 Store 只有一个 Store
所有 Store 都互不影响且是平级的 带有分层 reducer 的单一 Store
有单一调度器 没有调度器的概念
React 组件订阅 store 容器组件是有联系的
状态是可变的 状态是不可改变的

3.7. Redux 有哪些优点?

  • 结果的可预测性 - 由于总是存在一个真实来源,即 store ,因此不存在如何将当前状态与动作和应用的其他部分同步的问题。
  • 可维护性 - 代码变得更容易维护,具有可预测的结果和严格的结构。
  • 服务器端渲染 - 你只需将服务器上创建的 store 传到客户端即可。这对初始渲染非常有用,并且可以优化应用性能,从而提供更好的用户体验。
  • 开发人员工具 - 从操作到状态更改,开发人员可以实时跟踪应用中发生的所有事情。
  • 社区和生态系统 - Redux 背后有一个巨大的社区,这使得它更加迷人。一个由才华横溢的人组成的大型社区为库的改进做出了贡献,并开发了各种应用。
  • 易于测试 - Redux 的代码主要是小巧、纯粹和独立的功能。这使代码可测试且独立。
  • 组织 - Redux 准确地说明了代码的组织方式,这使得代码在团队使用时更加一致和简单。

4. React Router

4.1. 为什么需要 React 中的路由?

Router 用于定义多个路由,当用户定义特定的 URL 时,如果此 URL 与 Router 内定义的任何 “路由” 的路径匹配,则用户将重定向到该特定路由。所以基本上我们需要在自己的应用中添加一个 Router 库,允许创建多个路由,每个路由都会向我们提供一个独特的视图。

4.2. 什么是React 路由?

React 路由是一个构建在 React 之上的强大的路由库,它有助于向应用程序添加新的屏幕和流。这使 URL 与网页上显示的数据保持同步。它负责维护标准化的结构和行为,并用于开发单页 Web 应用。 React 路由有一个简单的API。

4.3. React Router 的优点。

  • 就像 React 基于组件一样,在 React Router v4 中,API 是 ‘All About Components’。可以将 Router 可视化为单个根组件(),其中我们将特定的子路由()包起来。
  • 无需手动设置历史值:在 React Router v4 中,我们要做的就是将路由包装在 组件中。
  • 包是分开的:共有三个包,分别用于 Web、Native 和 Core。这使我们应用更加紧凑。基于类似的编码风格很容易进行切换