前端面经-React

目录标题

一、react生命周期

react生命周期分为4个阶段:

挂载时(4个),更新时(5个),卸载时(1个),错误处理阶段(2个)。一共有12个钩子。

1.挂载时阶段(4个钩子):

  • constructor():加载时调用一次,可以实现:初始化state,为事件处理函数绑定实例。
  • static getDerivedStateFromProps(props, state):在组件每次更新时会调用,让组件在props变化时更新state,每次接收新的props之后都会返回一个对象作为新的state,如果返回null,则不更新任何内容。
  • render():类组件中唯一必须实现的方法,创建虚拟dom树,更新dom树都在此进行。
  • componentDidMount():组件挂载之后调用,只调用一次。一般在这里请求数据。

2.更新时阶段(5个钩子):

  • static getDerivedStateFromProps(props, state):在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
  • shouldComponentUpdate(nextProps, nextState):当 props 或 state 发生变化时,在渲染前调用,return true就会更新dom,return false能阻止更新。 仅作为性能优化的方式而存在。
  • render():render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。保持 render() 为纯函数,可以使组件更容易思考。
  • getSnapshotBeforeUpdate(prevProps, prevState):在最近一次的渲染提交到 DOM 节点之前调用,返回一个值,作为componentDidUpdate的第三个参数。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。
  • componentDidUpdate(prevProps, prevState, snapshot):会在更新后会被立即调用,首次渲染不会执行此方法。 当组件更新后,可以在此处对 DOM 进行操作、 进行网络请求 。

3.卸载时阶段(1个钩子)

componentWillUnmount():在组件卸载及销毁之前直接调用, 在此方法中执行必要的清理操作,例如,清楚timer,取消网络请求等等。

4.错误处理阶段(2个钩子)

  • static getDerivedStateFromError(error):在渲染阶段调用,它将抛出的错误作为参数,并返回一个值来更新state,不允许执行副作用。
  • componentDidCatch(error, info):在提交阶段被调用,用于记录错误,允许执行副作用。

二、Vue和React的区别

React 的思路是 HTML in JavaScript 也可以说是 All in JavaScript,通过 JavaScript 来生成 HTML,所以设计了 JSX 语法,还有通过 JS 来操作 CSS,社区的styled-component、JSS等。
Vue 是把 HTML,CSS,JavaScript 组合到一起,用各自的处理方式,Vue 有单文件组件,可以把 HTML、CSS、JS 写到一个文件中,HTML 提供了模板引擎来处理。

三、React函数式组件,如何给状态

(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)
(3). useState()说明:
参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()2种写法:
setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值

四、React diff

1、是什么

跟Vue一致,React通过引入Virtual DOM的概念,极大地避免无效的Dom操作,使我们的页面的构建效率提到了极大的提升
而diff算法就是更高效地通过对比新旧Virtual DOM来找出真正的Dom变化之处
传统diff算法通过循环递归对节点进行依次对比,效率低下,算法复杂度达到 O(n^3),react将算法进行一个优化,复杂度为O(n)

2、原理

react中diff算法主要遵循三个层级的策略:
tree层级
conponent 层级
element 层级

五、react中refs是什么?

refs是提供一种访问在render方法中创建DOM节点或者React元素的方法,在典型的数据流中,props是父子组件交互的唯一方式,想要修改子组件,需要使用新的props重新渲染它,某些情况下,在典型的数据流外,强制修改子代,这个时候可以使用refs

我们可以在组件添加一个ref属性来使用,该属性是一个回调函数,接收作为其第一个参数的底层DOM元素或组件挂载实例

input元素有一个ref属性,他的值是一个函数,该函数接收输入的实际DOM元素,然后将其放在实例上,这样就可以在 handleSubmit 函数内部访问它

六、React事件机制?

1、什么是合成事件

React基于浏览器的事件机制实现了一套自身的事件机制,它符合W3C规范,包括事件触发、事件冒泡、事件捕获、事件合成和事件派发等
React事件的设计动机(作用):

  • 在底层磨平不同浏览器的差异,React实现了统一的事件机制,我们不再需要处理浏览器事件机制方面的兼容问题,在上层面向开发者暴露稳定、统一的、与原生事件相同的事件接口
  • React把握了事件机制的主动权,实现了对所有事件的中心化管控
  • React引入事件池避免垃圾回收,在事件池中获取或释放事件对象,避免频繁的创建和销毁

2、React事件机制和原生DOM事件流有什么区别

虽然合成事件不是原生DOM事件,但它包含了原生DOM事件的引用,可以通过e.nativeEvent访问

3、DOM事件流是怎么工作的

一个页面往往会绑定多个事件,页面接收事件的顺序叫事件流
W3C标准事件的传播过程:

  1. 事件捕获
  2. 处于目标
  3. 事件冒泡

常用的事件处理性能优化手段:事件委托

把多个子元素同一类型的监听函数合并到父元素上,通过一个函数监听的行为叫事件委托 我们写的React事件是绑定在DOM上吗,如果不是绑定在哪里

4、React事件机制总结如下:

事件绑定 事件触发

  • React所有的事件绑定在container上(react17以后),而不是绑定在DOM元素上(作用:减少内存开销,所有的事件处理都在container上,其他节点没有绑定事件)
  • React自身实现了一套冒泡机制,不能通过return false阻止冒泡
  • React通过SytheticEvent实现了事件合成

5、React怎么阻止事件冒泡

  • 阻止合成事件的冒泡用e.stopPropagation()
  • 阻止合成事件和最外层document事件冒泡,使用e.nativeEvent.stopImmediatePropogation()
  • 阻止合成事件和除了最外层document事件冒泡,通过判断e.target避免

6、React性能优化手段

  • shouldComponentUpdate
  • memo
  • getDerviedStateFromProps
  • 使用Fragment
  • v-for使用正确的key 拆分尽可能小的可复用组件,ErrorBoundary
  • 使用React.lazy和React.Suspense延迟加载不需要立马使用的组件

七、state和props区别是什么?

相同点:都是普通的js对象,他们包含着影响渲染输出的信息

不同点:state是组件自己管理数据,控制自己的状态,可变

props是外部传入的数据参数,不可变

没有state的叫做无状态组件,有state的叫有状态组件

多用props,少用state

八、如何创建refs?

通过React.createRef()创建的,并通过ref属性附加到react元素,在构造组件中,

通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。

九、什么是高阶组件?

高阶组件(HOC)是接受一个组件并返回一个新组件的函数。基本上,这是一个模式,是从 React 的组合特性中衍生出来的,称其为纯组件,因为它们可以接受任何动态提供的子组件,但不会修改或复制输入组件中的任何行为

HOC 可以用于以下许多用例

  • 代码重用、逻辑和引导抽象
  • 渲染劫持
  • state 抽象和操作
  • props 处理

十、在构造函数调用super并将props作为参数传入的作用是啥?

在调用 super() 方法之前,子类构造函数无法使用this引用,ES6 子类也是如此。将 props 参数传递给 super() 调用的主要原因是在子构造函数中能够通过this.props来获取传入的 props。

props 的行为只有在构造函数中是不同的,在构造函数之外也是一样的

更多react面试题

十一、React18有哪些更新?

1、setState自动批处理

在react17中,只有react事件会进行批处理,原生js事件、promise,setTimeout、setInterval不会
react18,将所有事件都进行批处理,即多次setState会被合并为1次执行,提高了性能,在数据层,将多个状态更新合并成一次处理(在视图层,将多次渲染合并成一次渲染)

2、引入了新的root API,支持new concurrent renderer(并发模式的渲染)

3、去掉了对IE浏览器的支持,react18引入的新特性全部基于现代浏览器,如需支持需要退回到react17版本

十二、React的设计思想

组件化

每个组件都符合开放-封闭原则,封闭是针对渲染工作流来说的,指的是组件内部的状态都由自身维护,只处理内部的渲染逻辑。开放是针对组件通信来说的,指的是不同组件可以通过props(单项数据流)进行数据交互

数据驱动视图

UI=f(data)
通过上面这个公式得出,如果要渲染界面,不应该直接操作DOM,而是通过修改数据(state或prop),数据驱动视图更新

虚拟DOM

由浏览器的渲染流水线可知,DOM操作是一个昂贵的操作,很耗性能,因此产生了虚拟DOM。虚拟DOM是对真实DOM的映射,React通过新旧虚拟DOM对比,得到需要更新的部分,实现数据的增量更新

十三、JSX是什么,它和JS有什么区别

JSX是react的语法糖,它允许在html中写JS,它不能被浏览器直接识别,需要通过webpack、babel之类的编译工具转换为JS执行
JSX与JS的区别:

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

1、为什么在文件中没有使用react,也要在文件顶部import React from “react”

只要使用了jsx,就需要引用react,因为jsx本质就是React.createElement

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

jsx通过babel转义时,调用了React.createElement函数,它接收三个参数,分别是type元素类型,props元素属性,children子元素。从jsx到真实DOM需要经历jsx->虚拟DOM->真实DOM。如果组件首字母为小写,它会被当成字符串进行传递,在创建虚拟DOM的时候,就会把它当成一个html标签,而html没有app这个标签,就会报错。组件首字母为大写,它会当成一个变量进行传递,React知道它是个自定义组件就不会报错了

3、React组件为什么不能返回多个元素

这个问题也可以理解为React组件为什么只能有一个根元素,原因:

  1. React组件最后会编译为render函数,函数的返回值只能是1个,如果不用单独的根节点包裹,就会并列返回多个值,这在js中是不允许的
  2. react的虚拟DOM是一个树状结构,树的根节点只能是1个,如果有多个根节点,无法确认是在哪棵树上进行更新

vue的根节点为什么只有一个也是同样的原因

4、React组件怎样可以返回多个组件

  • 使用HOC(高阶函数)
  • 使用React.Fragment,可以让你将元素列表加到一个分组中,而且不会创建额外的节点(类似vue的template)
  • 使用数组返回

5、React中元素和组件的区别

  • react组件有类组件、函数组件
  • react元素是通过jsx创建的

十四、常用组件

1、错误边界

React部分组件的错误不应该导致整个应用崩溃,为了解决这个问题,React16引入了错误边界
使用方法:
React组件在内部定义了getDerivedStateFromError或者componentDidCatch,它就是一个错误边界。getDerviedStateFromError和componentDidCatch的区别是前者展示降级UI,后者记录具体的错误信息,它只能用于class组件
错误边界无法捕获自身的错误,也无法捕获事件处理、异步代码(setTimeout、requestAnimationFrame)、服务端渲染的错误

2、Portal

Portal提供了让子组件渲染在除了父组件之外的DOM节点的方式,它接收两个参数,第一个是需要渲染的React元素,第二个是渲染的地方(DOM元素)
用途:弹窗、提示框等

3、Fragment

Fragment提供了一种将子列表分组又不产生额外DOM节点的方法

4、Context

常规的组件数据传递是使用props,当一个嵌套组件向另一个嵌套组件传递数据时,props会被传递很多层,很多不需要用到props的组件也引入了数据,会造成数据来源不清晰,多余的变量定义等问题,Context提供了一种跨层级组件数据传递的方法

5、Suspense

Suspense使组件允许在某些操作结束后再进行渲染,比如接口请求,一般与React.lazy一起使用

十五、Redux工作原理

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

  • 跨层级组件数据共享与通信
  • 一些需要持久化的全局数据,比如用户登录信息
    Redux工作原理
  • 使用单例模式实现
  • Store 一个全局状态管理对象
  • Reducer 一个纯函数,根据旧state和props更新新state
  • Action 改变状态的唯一方式是dispatch action

十六、React-Router工作原理

1、为什么需要前端路由

  • 早期:一个页面对应一个路由,路由跳转导致页面刷新,用户体验差
  • ajax的出现使得不刷新页面也可以更新页面内容,出现了SPA(单页应用)。SPA不能记住用户操作,只有一个页面对URL做映射,SEO不友好
  • 前端路由帮助我们在仅有一个页面时记住用户进行了哪些操作

2、前端路由解决了什么问题

  • 当用户刷新页面,浏览器会根据当前URL对资源进行重定向(发起请求)
  • 单页面对服务端来说就是一套资源,怎么做到不同的URL映射不同的视图内容
  • 拦截用户的刷新操作,避免不必要的资源请求;感知URL的变化

3、react-router-dom有哪些组件

  • HashRouter/BrowserRouter 路由器
  • Route 路由匹配
  • Link 链接,在html中是个锚点
  • NavLink 当前活动链接
  • Switch 路由跳转
  • Redirect 路由重定向

React Router核心能力:跳转
路由负责定义路径和组件的映射关系
导航负责触发路由的改变
路由器根据Route定义的映射关系为新的路径匹配对应的逻辑
BrowserRouter使用的HTML5的history api实现路由跳转
HashRouter使用URL的hash属性控制路由跳转

4、前端通用路由解决方案

hash模式

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

history模式

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

十七、数据如何在React组件中流动

1、React组件通信

(1)react组件通信方式有哪些

组件通信的方式有很多种,可以分为以下几种:

  1. 父组件向子组件通信 =》props传递
  2. 子组件向父组件通信=》回调函数、事件冒泡、Ref
  3. 兄弟组件通信 =》实际上就是通过父组件中转数据的,子组件a传递给父组件,父组件再传递给子组件b
  4. 父组件向后代组件通信=》Context、HOC、
  5. 无关组件通信=》Redux

十八、React Hooks

1、React hooks解决了什么问题

在React16.8以前,常用的组件写法有class组件和function组件

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

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

why React hooks
优点:

  1. 告别难以理解的class组件
  2. 解决业务逻辑难以拆分的问题
  3. 使状态逻辑复用变的简单可行
  4. 函数组件从设计理念来看,更适合react

局限性:

  1. hooks还不能完整的为函数组件提供类组件的能力
  2. 函数组件给了我们一定程度的自由,却也对开发者的水平提出了更高的要求
  3. Hooks在使用层面有着严格的规则约束

十九、SetState是同步还是异步的

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

二十、fiber架构

1、什么是fiber,fiber解决了什么问题

在React16以前,React更新是通过树的深度优先遍历完成的,遍历是不能中断的,当树的层级深就会产生栈的层级过深,页面渲染速度变慢的问题,为了解决这个问题引入了fiber,React fiber就是虚拟DOM,它是一个链表结构,返回了return、children、siblings,分别代表父fiber,子fiber和兄弟fiber,随时可中断

2、Fiber是纤程,比线程更精细,表示对渲染线程实现更精细的控制

应用目的

  • 实现增量渲染,增量渲染指的是把一个渲染任务分解为多个渲染任务,而后将其分散到多个帧里。增量渲染是为了实现任务的可中断、可恢复,并按优先级处理任务,从而达到更顺滑的用户体验

Fiber的可中断、可恢复怎么实现的

  • fiber是协程,是比线程更小的单元,可以被人为中断和恢复,当react更新时间超过1帧时,会产生视觉卡顿的效果,因此我们可以通过fiber把浏览器渲染过程分段执行,每执行一会就让出主线程控制权,执行优先级更高的任务
  • fiber是一个链表结构,它有三个指针,分别记录了当前节点的下一个兄弟节点,子节点,父节点。当遍历中断时,它是可以恢复的,只需要保留当前节点的索引,就能根据索引找到对应的节点
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值