React面试题汇总

136 阅读8分钟

React的设计思想

  • 组件化
  • 数据驱动视图-UI=f(data)
  • 虚拟DOM

怎么防止HTML被转义?

dangerouslySetInnerHTML

vue和react的主要区别

1、vue是响应式的数据双向绑定系统,而react是单向数据流,没有双向绑定。

2、vue的语法较为简单,适用于小型项目创建,而react更适用于Web端和原生App的开发,侧重于大型应用。

3、vue拥有更快的渲染速度和更小的体积,react则拥有更大的生态圈,可以带来更多的工具支持。

3、模板渲染方式的不同

在表层上,模板的语法不同,React是通过JSX渲染模板。而Vue是通过一种拓展的HTML语法进行渲染

JSX是什么,它和JS有什么区别

JSX是react的语法糖,它允许在JS中写HTML,它不能被浏览器直接识别,需要通过webpack、babel之类的编译工具转换为JS执行(jsx本质就是React.createElement)

JSX与JS的区别:

  1. JS可以被打包工具直接编译,不需要额外转换,jsx需要通过babel编译,它是React.createElement的语法糖,使用jsx等价于React.createElement
  2. jsx是js的语法扩展,允许在html中写JS;JS是原生写法,需要通过script标签引入

为什么React自定义组件首字母要大写

jsx通过babel转义时,调用了React.createElement函数,它接收三个参数,分别是type元素类型,props元素属性,children子元素。

从jsx到真实DOM需要经历jsx->虚拟DOM->真实DOM。如果组件首字母为小写,它会被当成字符串进行传递,在创建虚拟DOM的时候,就会把它当成一个html标签,而html没有app这个标签,就会报错。组件首字母为大写,它会当成一个变量进行传递,React知道它是个自定义组件就不会报错了

简述React的生命周期

生命周期指的是组件实例从创建到销毁的流程,函数组件没有生命周期,只有类组件才有,因为只有class组件会创建组件实例

类组件的生命周期可以分为挂载、更新、卸载阶段

挂载

constructor 可以进行state和props的初始化

static getDerivedStateFromProps

render

componentDidMount 第一次渲染后调用,可以访问DOM,进行异步请求和定时器、消息订阅

更新

当组件的props或state变化会触发更新

static getDerivedStateFromProps

shouldComponentUpdate 返回一个布尔值,默认返回true,可以通过这个生命周期钩子进行性能优化,确认不需要更新组件时调用

render

getSnapShotBeforeUpdate

componentDidUpdate 在组件完成更新后调用

卸载

componentWillUnmount 组件从DOM中被移除的时候调用

错误捕获

static getDerivedStateFromError 在errorBoundary中使用

componentDidCatch

render是class组件中唯一必须实现的方法

React v16.0 前的类组件生命周期

  1. 挂载阶段:
  • constructor(构造函数)
  • componentWillMount(组件将要渲染)
  • render(渲染组件)
  • componentDidMount(组件渲染完成)
  1. 更新阶段: 分两种情况一种是 state 更新、一种是 props 更新
  • componentWillReceiveProps(组件 props 变更)
  • shouldComponentUpdate(组件是否渲染)
  • componentWillUpdate(组件将要更新)
  • render(渲染组件)
  • componentDidUpdate(组件更新完成)
  1. 卸载阶段:
  • componentWillUnmount(组件将要卸载)

React v16.0 后的类组件生命周期

  1. 挂载阶段:
  • constructor(构造函数)
  • getDerivedStateFromProps(派生 props)
  • render(渲染组件)
  • componentDidMount(组件渲染完成)
  1. 更新阶段:
  • getDerivedStateFromProps(派生 props)
  • shouldComponentUpdate(组件是否渲染)
  • render(渲染组件)
  • getSnapshotBeforeUpdate(获取快照)
  • componentDidUpdate(组件更新完成)
  1. 卸载阶段:
  • componentWillUnmount(组件将要卸载)

useEffect和useLayoutEffect区别

唯一的不同点就是useEffect是异步执行,而useLayoutEffect是同步执行的

react组件通信方式有哪些

  1. 父组件向子组件通信(利用React单向数据流的思想,通过props传递)
  2. 子组件向父组件通信(父组件向子组件传递一个函数,通过函数回调,拿到子组件传过来的值、ref、点击子组件的button按钮,事件会冒泡到父组件上)
  3. 兄弟组件通信(实际上就是通过父组件中转数据的,子组件a传递给父组件,父组件再传递给子组件b)
  4. 父组件向后代组件通信(context)
  5. 无关组件通信

Redux工作原理(使用单例模式实现)

Redux是一个状态管理库,使用场景:

  • 跨层级组件数据共享与通信
  • 一些需要持久化的全局数据,比如用户登录信息

Store 一个全局状态管理对象

Reducer 一个纯函数,根据旧state和props更新新state

Action 改变状态的唯一方式是dispatch action

前端通用路由解决方案

  • hash模式

改变URL以#分割的路径字符串,让页面感知路由变化的一种模式,通过hashchange事件触发

  • history模式

通过浏览器的history api实现,通过pushState事件触发

函数组件与类组件的区别:

  1. 类组件需要声明constructor,函数组件不需要
  2. 类组件需要手动绑定this,函数组件不需要
  3. 类组件有生命周期钩子,函数组件没有
  4. 类组件可以定义并维护自己的state,属于有状态组件,函数组件是无状态组件
  5. 类组件需要继承class,函数组件不需要
  6. 类组件使用的是面向对象的方法,封装:组件属性和方法都封装在组件内部 继承:通过extends React.Component继承;函数组件使用的是函数式编程思想

如何提高组件的渲染效率的

react 基于虚拟 DOM 和高效 Diff算法的完美配合,实现了对 DOM最小粒度的更新,大多数情况下,React对 DOM的渲染效率足以我们的业务日常

复杂业务场景下,性能问题依然会困扰我们。此时需要采取一些措施来提升运行性能,避免不必要的渲染则是业务中常见的优化手段之一

类组件:

  • 继承PureComponent
  • 使用shouldComponentUpdate优化

函数组件:

  • memo模拟PureComponent
  • 使用useMemo缓存变量
  • 使用useCallback缓存函数
  • 循环添加key, key最好用数组项的唯一值,不推荐用 index

高阶函数(Higher-order function),至少满足下列一个条件的函数

  • 接受一个或多个函数作为输入
  • 输出一个函数

在React中,高阶组件即接受一个或多个组件作为参数并且返回一个组件,本质也就是一个函数,并不是一个组件

const EnhancedComponent = highOrderComponent(WrappedComponent);

上述代码中,该函数接受一个组件 WrappedComponent 作为参数,返回加工过的新组件 EnhancedComponent

高阶组件的这种实现方式,本质上是一个装饰者设计模式

能用HOC做什么?

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

React 中 key 的重要性是什么?

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

你了解 Virtual DOM 吗?解释一下它的工作原理

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

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

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

SetState是同步还是异步的

setState是一个异步方法,但是在setTimeout/setInterval等定时器里逃脱了React对它的掌控,变成了同步方法

实现机制类似于vue的$nextTick和浏览器的事件循环机制,每个setState都会被react加入到任务队列,多次对同一个state使用setState只会返回最后一次的结果,因为它不是立刻就更新,而是先放在队列中,等时机成熟在执行批量更新。React18以后,使用了createRoot api后,所有setState都是异步批量执行的

setState在合成事件和生命周期函数中是异步的,在原生事件和定时器中都是同步的。

react18之前在生命周期函数和合成事件中表现为异步,在原生事件中表现为同步。 在react18优化批处理之后,在任何地方调用setState都会批处理,因此都表现为异步。

加分回答:setState本身不分同步或者异步,而是取决于是否处于batchupdate中。

组件中的所有函数在执行时临时设置一个变量isBatchingUpdates =true,当遇到setState时,如果isBatchingUpdates是true,那么setState就是异步的,如果是false,那么setState就是同步的。

那么什么时候isBatchingUpdates会被设置成false呢?

  • 当函数运行结束时isBatchingUpdates = false
  • 当函数遇到setTimeout、setInterval时isBatchingUpdates = false
  • 当dom添加自定义事件时isBatchingUpdates = false