2021年React常见的面试题以及答案(持续更新中

  • 无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props。

  • 所有 React 组件都必须是纯函数,并禁止修改其自身 props。

  • React是单项数据流,父组件改变了属性,那么子组件视图会更新。

  • 属性 props是外界传递过来的,状态 state是组件本身的,状态可以在组件中任意修改

  • 组件的属性和状态改变都会更新视图。

函数组件:

  • 函数组件接收一个单一的 props 对象并返回了一个React元素

  • 函数组件的性能比类组件的性能要高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。

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

===========================================================================================

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

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

  1. 每当底层数据发生改变时,整个 UI 都将在 Virtual DOM 描述中重新渲染。

  2. 然后计算之前 DOM 表示与新表示的之间的差异。

  3. 完成计算后,将只用实际更改的内容更新 real DOM。

说说对 State 和 Props的理解,有什么区别?

==========================================================================================

State

  • 一个组件的显示形态可以由数据状态和外部参数所决定,而数据状态就是state,一般在 constructor 中初始化

  • 当需要修改里面的值的状态需要通过调用setState来改变,从而达到更新组件内部数据的作用,并且重新调用组件render方法

  • setState还可以接受第二个参数,它是一个函数,会在setState调用完成并且组件开始重新渲染时被调用,可以用来监听渲染是否完成

Props

  • React的核心思想就是组件化思想,页面会被切分成一些独立的、可复用的组件,组件从概念上看就是一个函数,可以接受一个参数作为输入值,这个参数就是props,所以可以把props理解为从外部传入组件内部的数据

  • react具有单向数据流的特性,所以他的主要作用是从父组件向子组件中传递数据

  • props除了可以传字符串,数字,还可以传递对象,数组甚至是回调函数

  • 在子组件中,props在内部不可变的,如果想要改变它看,只能通过外部组件传入新的props来重新渲染子组件,否则子组件的props和展示形式不会改变

相同点

  • 两者都是 JavaScript 对象

  • 两者都是用于保存信息

  • props 和 state 都能触发渲染更新

区别

  • props 是外部传递给组件的,而 state 是在组件内被组件自己管理的,一般在 constructor 中初始化

  • props 在组件内部是不可修改的,但 state 在组件内部可以进行修改

  • state 是多变的、可以修改

说说对React refs 的理解?应用场景?

======================================================================================

是什么

React 中的 Refs提供了一种方式,允许我们访问 DOM节点或在 render方法中创建的 React元素。

本质为ReactDOM.render()返回的组件实例,如果是渲染组件则返回的是组件实例,如果渲染dom则返回的是具体的dom节点。

如何使用

  • 传入字符串,使用时通过 this.refs.传入的字符串的格式获取对应的元素

  • 传入对象,对象是通过 React.createRef() 方式创建出来,使用时获取到创建的对象中存在 current 属性就是对应的元素

  • 传入函数,该函数会在 DOM 被挂载时进行回调,这个函数会传入一个 元素对象,可以自己保存,使用时,直接拿到之前保存的元素对象即可

  • 传入hook,hook是通过 useRef() 方式创建,使用时通过生成hook对象的 current 属性就是对应的元素

应用场景

在某些情况下,我们会通过使用refs来更新组件,但这种方式并不推荐,过多使用refs,会使组件的实例或者是DOM结构暴露,违反组件封装的原则;

但下面的场景使用refs非常有用:

  • 对Dom元素的焦点控制、内容选择、控制

  • 对Dom元素的内容设置及媒体播放

  • 对Dom元素的操作和对组件实例的操作

  • 集成第三方 DOM 库

setState是同步还是异步

==============================================================================

setState本身并不是异步,之所以会有一种异步方法的表现形式,归根结底还是因为react框架本身的性能机制所导致的。因为每次调用setState都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少re-render调用。

实现同步:

  • setState提供了一个回调函数供开发者使用,在回调函数中,我们可以实时的获取到更新之后的数据。

state = {

number:1

};

componentDidMount(){

this.setState({number:3},()=>{

console.log(this.state.number) // 3

})

}

  • 利用setTimeout

state = {

number:1

};

componentDidMount(){

setTimeout(()=>{

this.setState({number:3})

console.log(this.state.number) //3

},0)

}

  • 还有在原生事件环境下

state = {

number:1

};

componentDidMount() {

document.body.addEventListener(‘click’, this.changeVal, false);

}

changeVal = () => {

this.setState({

number: 3

})

console.log(this.state.number) //3

}

super()和super(props)有什么区别?

=========================================================================================

在ES6中,通过extends关键字实现类的继承,super关键字实现调用父类,super代替的是父类的构建函数,使用super(xx)相当于调用sup.prototype.constructor.call(this.xx),如果在子类中不使用super关键字,则会引发报错

super()就是将父类中的this对象继承给子类的,没有super()子类就得不到this对象

在React中,类组件是基于es6的规范实现的,继承React.Component,因此如果用到constructor就必须写super()才初始化this,在调用super()的时候,我们一般都需要传入props作为参数,如果不传进去,React内部也会将其定义在组件实例中,所以无论有没有constructor,在render中this.props都是可以使用的,这是React自动附带的,但是也不建议使用super()代替super(props),因为在React会在类组件构造函数生成实例后再给this.props赋值,所以在不传递props在super的情况下,调用this.props为undefined,而传入props的则都能正常访问,确保了 this.props 在构造函数执行完毕之前已被赋值,更符合逻辑

总结

  • 在React中,类组件基于ES6,所以在constructor中必须使用super

  • 在调用super过程,无论是否传入props,React内部都会将porps赋值给组件实例porps属性中

  • 如果只调用了super(),那么this.props在super()和构造函数结束之间仍是undefined

说说对React事件机制的理解?

===============================================================================

是什么

React基于浏览器的事件机制自身实现了一套事件机制,包括事件注册、事件的合成、事件冒泡、事件派发等,在React中这套事件机制被称之为合成事件;

合成事件是 React模拟原生 DOM事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器

执行顺序

  • React 所有事件都挂载在 document 对象上

  • 当真实 DOM 元素触发事件,会冒泡到 document 对象后,再处理 React 事件

  • 所以会先执行原生事件,然后处理 React 事件

  • 最后真正执行 document 上挂载的事件

总结

  • React 上注册的事件最终会绑定在document这个 DOM 上,而不是 React 组件对应的 DOM(减少内存开销就是因为所有的事件都绑定在 document 上,其他节点没有绑定事件)

  • React 自身实现了一套事件冒泡机制,所以这也就是为什么我们 event.stopPropagation()无效的原因。

  • React 通过队列的形式,从触发的组件向父组件回溯,然后调用他们 JSX 中定义的 callback

  • React 有一套自己的合成事件 SyntheticEvent

了解更多详情请点击React事件机制的理解

React事件绑定的方式有哪些?区别?

==================================================================================

  • render方法中使用bind

  • render方法中使用箭头函数

  • constructor中bind

  • 定义阶段使用箭头函数绑定

class App extends React.Component {

handleClick() {

console.log('this > ', this);

}

render() {

return (

{/1.render方法中使用bind/}

test

{/*2.render方法中使用箭头函数 */}

)

}

}

class App extends React.Component {

constructor(props) {

super(props);

//3.constructor中bind

this.handleClick = this.handleClick.bind(this);

}

handleClick() {

console.log('this > ', this);

}

render() {

return (

test

)

}

}

class App extends React.Component {

//4.定义阶段使用箭头函数绑定

handleClick = () => {

console.log('this > ', this);

}

render() {

return (

test

)

}

}

区别

  • 编写方面:方式一、方式二写法简单,方式三的编写过于冗杂

  • 性能方面:方式一和方式二在每次组件render的时候都会生成新的方法实例,性能问题欠缺。若该函数作为属性值传给子组件的时候,都会导致额外的渲染。而方式三、方式四只会生成一个方法实例

  • 综合上述,方式四(箭头函数绑定)是最优的事件绑定方式

React组件生命周期有几个阶段

===============================================================================

  1. 初始渲染阶段这是组件即将开始其生命之旅并进入 DOM 的阶段。

getDefaultProps:获取实例的默认属性

getInitialState:获取每个实例的初始化状态

componentWillMount:组件即将被装载、渲染到页面上

render:组件在这里生成虚拟的 DOM 节点

componentDidMount:组件真正在被装载之后

  1. 更新阶段一旦组件被添加到 DOM,它只有在 prop 或状态发生变化时才可能更新和重新渲染。这些只发生在这个阶段。

componentWillReceiveProps:组件将要接收到属性的时候调用

shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了)

componentWillUpdate:组件即将更新不能修改属性和状态

render:组件重新描绘

componentDidUpdate:组件已经更新

  1. 卸载阶段这是组件生命周期的最后阶段,组件被销毁并从 DOM 中删除。

componentWillUnmount:组件即将销毁

详细解释 React 组件的生命周期方法

===================================================================================

  1. componentWillMount() – 在渲染之前执行,在客户端和服务器端都会执行。

  2. componentDidMount() – 仅在第一次渲染后在客户端执行。

  3. componentWillReceiveProps() – 当从父类接收到 props 并且在调用另一个渲染器之前调用。

  4. shouldComponentUpdate() – 根据特定条件返回 true 或 false。如果你希望更新组件,请返回true ,不想更新组件则返回 false就会阻止render渲染。默认情况下,它返回 true。

  5. componentWillUpdate() – 在 DOM 中进行渲染之前调用。

  6. componentDidUpdate() – 在渲染发生后立即调用。

  7. componentWillUnmount() – 从 DOM 卸载组件后调用。用于清理内存空间。

react在哪个生命周期做优化

==============================================================================

shouldComponentUpdate,这个方法用来判断是否需要调用 render 方法重绘 dom。

因为 dom 的描绘非常消耗性能,如果我们能在这个方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。

点击React学习笔记四——受控组件和非受控组件查看详解

受控组件和非受控组件的区别

============================================================================

受控组件是React控制的组件,input等表单输入框值不存在于 DOM 中,而是以我们的组件状态存在。每当我们想要更新值时,我们就像以前一样调用setState。

不受控制组件是您的表单数据由 DOM 处理,而不是React 组件,Refs 用于获取其当前值;

React组件事件代理的原理

=============================================================================

和原生HTML定义事件的唯一区别就是JSX采用驼峰写法来描述事件名称,大括号中仍然是标准的JavaScript表达式,返回一个事件处理函数。在JSX中你不需要关心什么时机去移除事件绑定,因为React会在对应的真实DOM节点移除时就自动解除了事件绑定。

React并不会真正的绑定事件到每一个具体的元素上,而是采用事件代理的模式:在根节点document上为每种事件添加唯一的Listener,然后通过事件的target找到真实的触发元素。这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件,React都会触发对应的事件处理函数。这就是所谓的React模拟事件系统。

为什么虚拟 dom 会提高性能

==============================================================================

虚拟dom(virtual dom) 是 JS对象,是一个真实dom的JS对象;虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。

用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。

React中的key有什么作用?

===============================================================================

跟Vue一样,React 也存在diff算法,而元素key属性的作用是用于判断元素是新创建的还是被移动的元素,从而减少不必要的Diff,因此key的值需要为每一个元素赋予一个确定的标识。

  • 如果列表数据渲染中,在数据后面插入一条数据,key作用并不大;前面的元素在diff算法中,前面的元素由于是完全相同的,并不会产生删除创建操作,在最后一个比较的时候,则需要插入到新的DOM树中。因此,在这种情况下,元素有无key属性意义并不大。

  • 如果列表数据渲染中,在前面插入数据时,当拥有key的时候,react根据key属性匹配原有树上的子元素以及最新树上的子元素,只需要将元素插入到最前面位置,当没有key的时候,所有的li标签都需要进行修改

  • 并不是拥有key值代表性能越高,如果说只是文本内容改变了,不写key反而性能和效率更高,主要是因为不写key是将所有的文本内容替换一下,节点不会发生变化,而写key则涉及到了节点的增和删,发现旧key不存在了,则将其删除,新key在之前没有,则插入,这就增加性能的开销

总结

良好使用key属性是性能优化的非常关键的一步,注意事项为:

  • key 应该是唯一的

  • key不要使用随机值(随机数在下一次 render 时,会重新生成一个数字)

  • 避免使用 index 作为 key

react的diff算法是怎么完成的

=================================================================================

  • 把树形结构按照层级分解,只比较同级元素

  • 通过给列表结构的每个单元添加的唯一 key值进行区分同层次的子节点的比较。

  • React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)

  • 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty. 到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制。

  • 选择性渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。

在这里插入图片描述

react组件之间如何通信

============================================================================

  • 父子:父传子:props; 子传父:子调用父组件中的函数并传参;

  • 兄弟:利用redux实现和利用父组件

  • 所有关系都通用的方法:利用PubSub.js订阅

点击React学习笔记十二——组件之间的通信方式查看详细内容

什么是高阶组件?

=======================================================================

高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。基本上,这是从React的组成性质派生的一种模式,我们称它们为“纯”组件, 因为它们可以接受任何动态提供的子组件,但它们不会修改或复制其输入组件的任何行为。

  • 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧

  • 高阶组件的参数为一个组件返回一个新的组件

  • 组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件

点击对高阶组件的理解查看详解

说说对React Hooks的理解?解决了什么问题?

=========================================================================================

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性,因此,现在的函数组件也可以是有状态的组件,内部也可以维护自身的状态以及做一些逻辑方面的处理;

最常见的hooks有:useState、useEffect

hooks的出现,使函数组件的功能得到了扩充,拥有了类组件相似的功能;

点击React学习笔记十一——扩展知识点(setState / lazyLoad / Hook / Fragment / Context)查看其中的Hook知识点详解

说说react中引入css的方式有哪几种?区别?

=======================================================================================

组件式开发选择合适的css解决方案尤为重要,而在react中,引入CSS就不如Vue方便简洁,其引入css的方式有很多种,各有利弊;

  • 在组件内直接使用

  • 组件中引入 .css 文件

  • 组件中引入 .module.css 文件

  • CSS in JS

点击 react中引入css的方式查看以上几种引入方式的代码案例

区别

  • 在组件内直接使用css该方式编写方便,容易能够根据状态修改样式属性,但是大量的演示编写容易导致代码混乱

  • 组件中引入 .css 文件符合我们日常的编写习惯,但是作用域是全局的,样式之间会层叠

  • 引入.module.css 文件能够解决局部作用域问题,但是不方便动态修改样式,需要使用内联的方式进行样式的编写

  • 通过css in js 这种方法,可以满足大部分场景的应用,可以类似于预处理器一样样式嵌套、定义、修改状态等

  • 至于使用react用哪种方案引入css,并没有一个绝对的答案,可以根据各自情况选择合适的方案

在React中组件间过渡动画如何实现?

==================================================================================

在react中,react-transition-group是一种很好的解决方案,其为元素添加enter,enter-active,exit,exit-active这一系列勾子,可以帮助我们方便的实现组件的入场和离场动画

其主要提供了三个主要的组件:

  • CSSTransition:在前端开发中,结合 CSS 来完成过渡动画效果

  • SwitchTransition:两个组件显示和隐藏切换时,使用该组件

  • TransitionGroup:将多个动画组件包裹在其中,一般用于列表中元素的动画

React中组件间过渡动画查看以上过度组件案例详解

React context是什么?

================================================================================

简单说就是,当你不想在组件树中通过逐层传递props或者state的方式来传递数据时,可以使用Context来实现跨层级的组件数据传递。

在这里插入图片描述

使用props或者state传递数据,数据自顶下流。

在这里插入图片描述

使用Context,可以跨越组件进行数据传递。

说说你对Redux的理解?其工作原理?

==================================================================================

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值