【面试题】2023年最新前端面试题-react篇

原文见:语雀(https://www.yuque.com/deepstates/interview/hia3k3)

● 核心概念
○ 元素渲染、组件、props、state
○ refs:使用场景、如何创建、如何访问
○ 组件通信:父子、祖孙、兄弟组件通信
○ 生命周期、事件处理、条件渲染、列表的key、表单、状态提升、组合&继承

⭐️⭐️⭐️ 相关知识参考:

说说你对react的理解?
是什么:react是构建用户界面的js库
能干什么:可以用组件化的方式构建快速响应的web应用程序
如何干:声明式(jsx) 组件化(方便拆分和复用 高内聚 低耦合) 一次学习随处编写
做的怎么样: 优缺(社区繁荣 一次学习随处编写 api简介)缺点(没有系统解决方案 选型成本高 过于灵活)
设计理念:跨平台(虚拟dom) 快速响应(异步可中断 增量更新)
性能瓶颈:cpu io fiber时间片 concurrent mode
渲染过程:scheduler render commit Fiber架构

React有什么特点?
● 声明式设计:react采用范式声明,开发者只需要声明显示内容,react就会自动完成
● 高效: react通过对dom的模拟(也就是虚拟dom),最大限度的减少与dom的交互
● 灵活: react可以和已知的库或者框架很好配合
● 组件: 通过react构建组件,让代码更容易复用,能够很好应用在大型项目开发中,把页面功能拆分成小模块 每个小模块就是组件
● 单向数据流: react是单向数据流,数据通过props从父节点传递到子节点,如果父级的某个props改变了,react会重新渲染所有的子节点

列出React的一些主要优点?

  1. 通过虚拟 DOM 提高应用程序的性能。
  2. JSX 使代码易于阅读和编写。
  3. 它在客户端和服务器端都能进行渲染(SSR)。
  4. 易于与框架(Angular, Backbone)集成,因为它只是一个视图库。
  5. 使用 Jest 等工具容易编写单元和集成测试。

React有哪些限制?

  1. React 只是一个视图库,不是一个完整的框架。
  2. 对于刚接触网络开发的初学者来说,有一个学习曲线。
  3. 将 React 整合到传统的 MVC 框架中需要一些额外的配置。
  4. 代码的复杂性随着内联模板和 JSX 的增加而增加。
  5. 太多的小组件导致了过度工程化或模板化。

如何模块化 React 中的代码?
可以使用export、import属性来模块化代码。它们有助于在不同的文件中单独编写组件。

对 React-Intl 的理解,它的工作原理?
● React-intl是雅虎的语言国际化开源项目FormatJS的一部分,通过其提供的组件和API可以与ReactJS绑定。
● React-intl提供了两种使用方法,一种是引用React组件,另一种是直接调取API,官方更加推荐在React项目中使用前者,只有在无法使用React组件的地方,才应该调用框架提供的API。它提供了一系列的React组件,包括数字格式化、字符串格式化、日期格式化等。
● 在React-intl中,可以配置不同的语言包,他的工作原理就是根据需要,在语言包之间进行切换。

区别

react vs vue?/ vue 与react的区别?(大华、阿里)
一、相同点:
● 都支持服务器渲染
● 都有虚拟dom,组件化开发,通过props参数进行父子组件数据的传递,都实现webcomponent规范
● 都是数据驱动视图
● 都有状态管理,react有redux,vue有vuex
● 都有支持native的方案 react有react native vue有weex
二、不同点:
● react严格上只针对mvc的view层,vue是mvvm模式
● 模板渲染方式不同
○ 模板的语法不同,React是通过jsx渲染,vue是通过一种拓展的html语法进行渲染。
○ 模板的原理不同:React是在组件JS代码中,通过原生JS实现模板中的常见语法,如插值、条件、循环等,都是通过JS语法实现的,更加纯粹更加原生。Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要v-if来实现这一点。
● 虚拟dom不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个dom组件树,而react不同,当应用的状态被改变时,全部组件都会重新渲染,所以react中用shouldcomponentupdate这个生命周期的钩子函数来控制
● 组件写法不一样 ,react是jsx和inline style ,就是把html和css全写进js中,vue则是html,css ,js在同一个文件
● 数据绑定不一样,vue实现了数据双向绑定,react数据流动是单向的
● 在react中,state对象需要用setstate方法更新状态,在vue中,state对象不是必须的,数据由data属性在vue对象中管理

vue, react 适用场景? / vue, react 技术选型?
● 应用需要尽可能小和快就用vue, vue渲染速度比react 快
● 大型项目建议用react,因为vue模板的使用不容易发现错误、也不易拆分和测试
● 如果要适用于web 和原生app的项目,就使用react native

vue、react的区别和联系?()
vue, react的模板渲染、两者的虚拟dom、diff差异(vue2、vue3、react16)、两者的批量更新,还有路由差异、常用的优化手段、怎么进行数据通信、讲点新鲜的内容:vue3有什么特性、最后总结,谈谈两者的如今的生态。。。
React核心
核心概念
组件
你对组件的理解?
可组合,可复用,可维护,可测试

React声明组件有哪几种方法,有什么不同?/ React中有哪几种构建组件的方式?
一、React 声明组件的三种方式:
● 无状态函数式组件
○ 它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到state状态的操作
○ 组件不会被实例化,整体渲染性能得到提升,不能访问this对象,不能访问生命周期的方法
● ES5 原生方式 React.createClass定义的组件 // RFC
○ React.createClass会自绑定函数方法,导致不必要的性能开销,增加代码过时的可能性。
● ES6继承形式 extends React.Component定义的组件 // RCC
○ 目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用。
二、区别
1、无状态组件相对于于后者的区别:
(1)与无状态组件相比,React.createClass和React.Component都是创建有状态的组件,这些组件是要被实例化的,并且可以访问组件的生命周期方法。
2、React.createClass与React.Component区别:
(1)函数this自绑定
● React.createClass创建的组件,其每一个成员函数的this都有React自动绑定,函数中的this会被正确设置。
● React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。
(2)组件属性类型propTypes及其默认props属性defaultProps配置不同
● React.createClass在创建组件时,有关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是使用getDefaultProps的方法来获取默认组件属性的
● React.Component在创建组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。
(3)组件初始状态state的配置不同
● React.createClass创建的组件,其状态state是通过getInitialState方法来配置组件相关的状态;
● React.Component创建的组件,其状态state是在constructor中像初始化组件属性一样声明的。

React 中构建组件的方式?
● 自定义组件:函数组件或者无状态组件 ,组件首字母大写
● 类组件:一个类组件必须实现一个render方法,这个方法必须返回一个jsx元素,要用一个外层的元素把所有内容包裹起来

你怎样理解“在React中,一切都是组件”这句话?

Component, Element, Instance 之间有什么区别和联系?
● 元素:一个元素element是一个普通对象(plain object),描述了对于一个DOM节点或者其他组件component,你想让它在屏幕上呈现成什么样子。元素element可以在它的属性props中包含其他元素(译注:用于形成元素树)。创建一个React元素element成本很低。元素element创建之后是不可变的。
● 组件:一个组件component可以通过多种方式声明。可以是带有一个render()方法的类,简单点也可以定义为一个函数。这两种情况下,它都把属性props作为输入,把返回的一棵元素树作为输出。
● 实例:一个实例instance是你在所写的组件类component class中使用关键字this所指向的东西(译注:组件实例)。它用来存储本地状态和响应生命周期事件很有用。
函数式组件(Functional component)根本没有实例instance。类组件(Class component)有实例instance,但是永远也不需要直接创建一个组件的实例,因为React帮我们做了这些。

如何有条件地向React组件添加属性?
对于某些属性,React非常聪明,如果传递给它的值是虚值,可以省略该属性。
var InputComponent = React.createClass({
render: function() {
var required = true;
var disabled = false;

return(
  
)

}
})
渲染结果:

另一种可能的方法是:
var condition = true;

var component = (

有状态组件、无状态组件
区分有状态和无状态组件?
有状态组件 无状态组件
1、在内存中存储有关组件状态变化的信息 1、计算组件的内部的状态
2、有权改变状态 2、无权改变状态
3、包含过去、现在和未来可能的状态变化情况 3、不包含过去、现在和未来可能的状态变化情况
4、接收无状态组件状态变化要求的通知,然后将props发送给他们 4、从有状态组件接收props并将其视为回调函数

对有状态组件和无状态组件的理解及使用场景
一、有状态组件
1、特点:
● 是类组件
● 有继承
● 可以使用this
● 可以使用react的生命周期
● 使用较多,容易频繁触发生命周期钩子函数,影响性能
● 内部使用 state,维护自身状态的变化,有状态组件根据外部组件传入的 props 和自身的 state进行渲染。
2、使用场景:
● 需要使用到状态的。
● 需要使用状态操作组件的(无状态组件的也可以实现新版本react hooks也可实现)
3、总结:
类组件可以维护自身的状态变量,即组件的 state ,类组件还有不同的生命周期方法,可以让开发者能够在组件的不同阶段(挂载、更新、卸载),对组件做更多的控制。类组件则既可以充当无状态组件,也可以充当有状态组件。当一个类组件不需要管理自身状态时,也可称为无状态组件。
二、无状态组件
1、特点:
● 不依赖自身的状态state
● 可以是类组件或者函数组件。
● 可以完全避免使用 this 关键字。(由于使用的是箭头函数事件无需绑定)
● 有更高的性能。当不需要使用生命周期钩子时,应该首先使用无状态函数组件
● 组件内部不维护 state ,只根据外部组件传入的 props 进行渲染的组件,当 props 改变时,组件重新渲染。
2、使用场景:
● 组件不需要管理 state,纯展示
3、优点:
● 简化代码、专注于 render
● 组件不需要被实例化,无生命周期,提升性能。输出(渲染)只取决于输入(属性),无副作用
● 视图和数据的解耦分离
4、缺点:
● 无法使用 ref
● 无生命周期方法
● 无法控制组件的重渲染,因为无法使用shouldComponentUpdate 方法,当组件接受到新的属性时则会重渲染
三、总结:
组件内部状态且与外部无关的组件,可以考虑用状态组件,这样状态树就不会过于复杂,易于理解和管理。当一个组件不需要管理自身状态时,也就是无状态组件,应该优先设计为函数组件。比如自定义的 、 等组件。

函数组件、类组件
函数组件(Functional component,也称哑组件,或展示组件,或hooks组件)和类组件(Class component)的相同点和不同点?(税友)
一、相同点:都可以接收props返回react元素
二、不同点:
● 编程思想:类组件需要创建实例,面向对象,函数组件不需要创建实例,接收输入,返回输出,函数式编程
● 内存占用:类组建需要创建并保存实例,占用一定的内存
● 值捕获特性:函数组件具有值捕获的特性 。function组件能捕获渲染的值(captaure the rendered values),读取渲染闭包内的数据,而class组件在react通过this.的方式读取,this是可变的,所以总能获取最新的props
● 状态:类组件有自己的状态,函数组件没有,只能通过useState。Class把state属性挂载的对象保存到memoizedState属性中,而Function是用链表来保存状态的,memoizedState属性保存是链表的头指针。
● 生命周期:类组件有完整生命周期,函数组件没有,可以使用useEffect实现类似的生命周期
● 可测试性:函数组件方便测试
● 逻辑复用:类组件继承 Hoc(逻辑混乱 嵌套),组合优于继承,函数组件hook逻辑复用
● 跳过更新:shouldComponentUpdate PureComponent,React.memo
● 发展未来:函数组件将成为主流,屏蔽this、规范、复用,适合时间分片和渲染

类组件
为什么类方法需要绑定到类实例?
在JS中,this值会根据当前上下文变化。
在React类组件方法中,开发人员通常希望this引用组件的当前实例。因此有必要将这些方法绑定到实例。
通常,这是在构造函数中完成的。

在构造函数中调用super的目的是什么?/ 在构造函数调用super并将props作为参数传入的作用是啥?
在调用super()方法之前,子类构造函数无法使用this引用,子类必须在 constructor 中调用 super()。将props参数传递给super()调用的主要原因是在子构造函数中能够在constructor通过this.props来获取传入的props
● 传递props
class MyComponent extends React.Component {
constructor(props) {
super(props);
console.log(this.props); // { name: ‘sudheer’, age: 30 }
}
}
● 没传递props
class MyComponent extends React.Component {
constructor(props) {
super();
console.log(this.props); // undefined
// 但是Props参数仍然可用
console.log(props); // Prints { name: ‘sudheer’, age: 30 }
}

render() {
// 构造函数外部不受影响
console.log(this.props); // { name: ‘sudheer’, age: 30 }
}
}

渲染组件
UI组件、容器组件
展示组件(Presentational component)和容器组件(Container component)之间有何不同?
根据组件的职责通常把组件分为 UI 组件和容器组件。
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
两者通过 React-Redux 提供 connect 方法联系起来。

受控组件、非受控组件
何为受控组件(controlled component)?
React负责渲染表单的组件,值是来自于state控制的输入表单元素称为受控组件

你对受控组件和非受控组件了解多少? / 什么是受控组件? 什么是非受控组件?
● 受控组件是React控制中的组件,并且是表单数据真实的唯一来源。
● 非受控组件是由DOM处理表单数据的地方,而不是在React组件中。
尽管非受控组件通常更易于实现,因为只需使用refs即可从DOM中获取值,但通常建议优先选择受控制的组件,而不是非受控制的组件。
这样做的主要原因是受控组件支持即时字段验证,允许有条件地禁用/启用按钮,强制输入格式。
受控组件 非受控组件
1、没有维持自己的状态 1、保持着自己的状态
2、数据由父组件控制 2、数据由dom控制
3、通过props获取当前值,然后通过回调通知更改 3、refs用于获取当前值

props
区分状态(state)和 属性(props)?/ (组件的)状态(state)和属性(props)之间有何不同?
● Props是一个从外部传进组件的参数,主要作用就是父组件向子组件传递数据,但是props对于使用它的组件来说是只读的,一旦赋值不能修改,只能通过外部组件主动传入新的props来重新渲染子组件
● State 一个组件的显示形态可以由数据状态和外部参数决定,外部参数是props,数据状态就是state,首先,在组件初始化的时候,用this.state给组件设定一个初始的state,在第一次渲染的时候就会用这个数据来渲染组件,state不同于props一点是,state可以修改,通过this.setState()方法来修改state
条件 state props
从父组件中接收初始值 yes yes
从父组件可以改变值 no yes
在组件中设置默认值 yes yes
在组件的内部变化 yes no
设置子组件的初始值 yes yes
在子组件的内部更改 no yes

纯函数
什么是纯函数?
纯函数是不依赖并且不会在其作用域之外修改变量状态的函数。本质上,纯函数始终在给定相同参数的情况下返回相同结果。

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

如何更新组件的状态
this.setState()、useState

当调用setState时,React render是如何工作的?
可以将render分为两个步骤
● 虚拟DOM渲染:当render方法被调用时,它返回一个新的组件的虚拟DOM结构。当调用setState()时,render会被再次调用,因为默认情况下shouldComponentUpdate总是返回true,所以默认情况下React是没有优化的。
● 原生DOM渲染:React只会在虚拟DOM中修改真实DOM节点,而且修改的次数非常少——这是很棒的React特性,它优化了真实DOM的变化,使React变得更快。

setState
调用 setState 之后发生了什么?
React在调用setstate后,react会将传入的参数对象和组件当前的状态合并,触发调和过程,
在调和过程中,react会根据新的状态构建react元素树重新渲染整个UI界面,在得到元素树之后,react会自动计算新老节点的差异,根据差异对界面进行最小化重新渲染

setState是同步的还是异步的?
一、setState 并不是单纯同步/异步的,它的表现会因调用场景的不同而不同:
● 在 React 钩子函数及合成事件中,它表现为异步;
● 同步:
○ DOM 原生事件中(绕过React通过addEventListener直接添加的事件处理函数)
○ 通过setTimeout/setInterval产生的异步调用
二、这种差异,本质上是由 React 事务机制和批量更新机制的工作方式来决定的:在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

为什么建议传递给 setState 的参数是一个 callback 而不是一个对象
因为在setstate中,props和state可能会异步更新,也就是说,对相同的变量进行处理的时候,会将这多次处理合并为一个,这个是批处理;而如果传入函数,那么会进行链式调用,这个函数会被react加入到一个执行队列中,函数中的代码会依次执行。

Refs

React 中 refs 的作用是什么?
Refs提供了一种访问在render方法中创建的 DOM 节点或者 React 元素的方法。在典型的数据流中,props是父子组件交互的唯一方式,想要修改子组件,需要使用新的pros重新渲染它。凡事有例外,某些情况下需要在典型数据流外,强制修改子代,这个时候可以使用Refs
class CustomForm extends Component {
handleSubmit = () => {
console.log("Input Value: ", this.input.value)
}
render () {
return (

type=‘text’
ref={(input) => this.input = input} />
Submit

)
}
}
上述代码中的 input 域包含了一个 ref 属性,该属性声明的回调函数会接收 input 对应的 DOM 元素,我们将其绑定到 this 指针以便在其他的类函数中使用。
● refs 并不是类组件的专属,函数式组件同样能够利用闭包暂存其值:
function CustomForm ({handleSubmit}) {
let inputElement
return (

handleSubmit(inputElement.value)}>
type=‘text’
ref={(input) => inputElement = input} />
Submit

)
}

列出一些应该使用 Refs 的情况?
1.需要管理焦点、选择文本或媒体播放时
2.触发式动画
3.与第三方 DOM 库集成

如何创建refs
● 回调函数
● React.createRef():refs是使用React.createRef()创建的,并通过ref属性附加到React元素。在构造组件时,通常将Refs分配给实例属性,以便可以在整个组件中引用它们
● useRef()

React如何获取组件对应的DOM元素?
可以用ref来获取某个子节点的实例,然后通过当前class组件实例的一些特定属性来直接获取子节点实例。ref有三种实现方法:
● 字符串格式:字符串格式,这是React16版本之前用得最多的,例如:

span


● 函数格式:ref对应一个方法,该方法有一个参数,也就是对应的节点实例,例如:

this.info = ele}>
● createRef方法:React 16提供的一个API,使用React.createRef()来实现
● useRef

React中可以在render访问refs吗?为什么?
不可以,render 阶段 DOM 还没有生成,无法获取 DOM。DOM 的获取需要在 pre-commit 阶段和 commit 阶段。

组件通信
父子组件通信?
● 正向传值:父组件 -> 子组件
○ props
● 逆向传值:子组件 -> 父组件
○ props + 回调
● 订阅-发布
● redux

跨级组件方式?
● 逐层传值
○ 父 -> 子 -> 孙…,通过props往下传,通过回调往上传
● 跨级传值
○ context
● 订阅-发布
● redux

兄弟组件通信方式?
● 通过兄弟节点的共同父节点,由父节点转发消息
● 浏览器存储:使用sessionStorage、localStorage
● 路由传值:如果两个组件之间存在跳转,可以使用路由跳转赋值
● 订阅-发布
● redux

生命周期
react 生命周期函数有哪些不同阶段?
一、在组件生命周期中有4个不同的阶段:

  1. Initialzation 初始化状态:在这个阶段,组件准备设置初始化状态和默认属性
  2. Mounting:react组件已经准备好挂载到浏览器DOM中。这个阶段包括constructor、getDerivedStateFromProps、render、componentDidMount
  3. updating 更新阶段:在这个阶段,组件以两种方式更新,发送新的props和state状态。此阶段包括getDerivedStateFromProps、shouldComponentUpdate、render、getSnapshotBeforeUpdate、componentDidUpdate
  4. Unmounting 卸载阶段:在这个阶段,组件已经不再被需要了,它从浏览器DOM中卸载下来。这个阶段包含componentWillUnmount生命周期方法。
    二、还有一个错误处理的阶段
  5. Error Handling:在这个阶段,不论在渲染的过程中,还是在生命周期方法中,或是在任何子组件的构造函数中发生错误,该组件都会被调用。这个阶段包含了static getDerivedStateFromError()、componentDidCatch生命周期方法。

react生命周期方法有哪些?
一、React的生命周期中常用的有:
● constructor,负责数据初始化。
● render,将jsx转换成真实的dom节点。
● componentDidMount,组件第一次渲染完成时触发。可以在这里做AJAX请求,DOM的操作或状态更新以及设置事件监听器。
● componentDidUpdate,组件更新完成时触发。它主要用于更新DOM以响应props或state更改。
● componentWillUnmount,组件销毁和卸载时触发。它用于取消任何的网络请求,或删除与组件关联的所有事件监听器。
二、不常用的有:
● getDerivedStateFromProps,更新state和处理回调。
● shouldComponentUpdate,用于性能优化。
● getSnapshotBeforeUpdate,替代了componentWillUpdate。

render
怎样解释 React 中 render() 的目的?
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如、、

等。此函数必须保持纯净,即必须每次调用时都返回相同的结果

类组件的render方法执行后最终返回的结果是什么
jsx对象

怎么阻止组件渲染?
在组件的 render 方法中返回 null 并不会影响触发组件的生命周期方法

哪些方法会触发 React 重新渲染?重新渲染 render 会做些什么?
1)哪些方法会触发 react 重新渲染?
● setState()方法被调用
setState 是 React 中最常用的命令,通常情况下,执行 setState 会触发 render。但是这里有个点值得关注,执行 setState 的时候不一定会重新渲染。当 setState 传入 null 时,并不会触发 render。
class App extends React.Component {
state = {
a: 1
};

render() {
console.log(“render”);
return (

{this.state.a}


你可能感兴趣的:(前端,react.js,javascript)