2022社招react面试题 附答案

React视频解说 点击学习

1、React的申请应该放在哪个⽣命周期中?

React的异步申请到底应该放在哪个⽣命周期⾥,有⼈认为在componentWillMount中能够提前进⾏异步申请,防止⽩屏,其实这个观点是有问题的。

因为JavaScript中异步事件的性质,当您启动API调⽤时,浏览器会在此期间返回执⾏其余⼯作。当React渲染⼀个组件时,它不会期待componentWillMount它实现任何事件。React继续前进并持续render,没有方法“暂停”渲染以期待数据达到。

⽽且在componentWillMount申请会有⼀系列潜在的问题。⾸先,在服务器渲染时,如果在componentWillMount⾥获取数据,fetch data会执⾏两次,⼀次在服务端⼀次在客户端,这造成了多余的申请。其次,在React 16进⾏React Fiber重写后, componentWillMount可能在⼀次渲染中屡次调⽤。

⽬前官⽅举荐的异步申请是在componentDidmount中进⾏。如果有非凡需要须要提前申请,也能够在非凡状况下在constructor中申请。react 17之后 componentWillMount会被废除,仅仅保留UNSAFE_componentWillMount。

2、jsx的实质是什么?

首先理解下jsx是什么

  1. JSX是一种JavaScript的语法扩大(eXtension),也在很多中央称之为JavaScript XML,因为看起就是一段XML语法;
  2. 它用于形容咱们的UI界面,并且其实现能够和JavaScript交融在一起应用;
  3. 它不同于Vue中的模块语法,你不须要专门学习模块语法中的一些指令(比方v-for、v-if、v-else、v-bind)。

JSX其实是嵌入到JavaScript中的一种构造语法。

实际上,jsx仅仅只是React.createElement(component, props, ...children)函数的语法糖。所有的jsx最终都会被转换成React.createElement的函数调用。

createElement须要传递三个参数

参数一:type

  • 以后ReactElement的类型;
  • 如果是标签元素,那么就应用字符串示意 “div”;
  • 如果是组件元素,那么就间接应用组件的名称;

参数二:config

  • 所有jsx中的属性都在config中以对象的属性和值的模式存储

参数三:children

  • 寄存在标签中的内容,以children数组的形式进行存储;
  • 当然,如果是多个元素呢?React外部有对它们进行解决,解决的源码在下方

3、React最新的⽣命周期是怎么的?

React 16之后有三个⽣命周期被废除(但并未删除)

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

官⽅打算在17版本齐全删除这三个函数,只保留UNSAVE_前缀的三个函数,⽬的是为了向下兼容,然而对于开发者⽽⾔应该尽量避免使⽤他们,⽽是使⽤新增的⽣命周期函数代替它们。

⽬前React16.8+的⽣命周期分为三个阶段,别离是挂载阶段、更新阶段、卸载阶段。

挂载阶段:

  • constructor:构造函数,最先被执⾏,咱们通常在构造函数⾥初始化state对象或者给⾃定义⽅法绑定this;
  • getDerivedStateFromProps:static getDerivedStateFromProps(nextProps, prevState),这是个动态⽅法,当咱们接管到新的属性想去批改咱们state, 能够使⽤getDerivedStateFromProps
  • render:render函数是纯函数,只返回须要渲染的东⻄,不应该蕴含其它的业务逻辑,能够返回原⽣的DOM、React组件、Fragment、Portals、字符串和数字、 Boolean和null等内容;
  • componentDidMount:组件装载之后调⽤,此时咱们能够获取到DOM节点并操作,⽐如对canvas,svg的操作,服务器申请,订阅都能够写在这个⾥⾯,然而记得在componentWillUnmount中勾销订阅;

更新阶段:

  • getDerivedStateFromProps: 此⽅法在更新个挂载阶段都可能会调⽤;
  • shouldComponentUpdate:shouldComponentUpdate(nextProps, nextState),有两个参数nextProps和nextState,示意新的属性和变动之后的state,返回⼀个布尔值,true示意会触发从新渲染,false示意不会触发从新渲染,默认返回true,咱们通常利⽤此⽣命周期来优化React程序性能;
  • render:更新阶段也会触发此⽣命周期;
  • getSnapshotBeforeUpdate:getSnapshotBeforeUpdate(prevProps, prevState),这个⽅法在render之后,componentDidUpdate之前调⽤,有两个参数prevProps和prevState,示意之前的属性和之前的state,这个函数有⼀个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,能够返回null,此⽣命周期必须与componentDidUpdate搭配使⽤;
  • componentDidUpdate:componentDidUpdate(prevProps, prevState, snapshot),该⽅法在getSnapshotBeforeUpdate⽅法之后被调⽤,有三个参数prevProps,prevState,snapshot,示意之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate返回的,如果触发某些回调函数时须要⽤到DOM元素的状态,则将对⽐或计算的过程迁徙⾄getSnapshotBeforeUpdate,而后在componentDidUpdate中统⼀触发回调或更新状态。

卸载阶段:

-componentWillUnmount:当咱们的组件被卸载或者销毁了就会调⽤,咱们能够在这个函数⾥去革除⼀些定时器,勾销⽹络申请,清理⽆效的DOM元素等垃圾清理⼯作。

总结:

  • componentWillMount:在渲染之前执行,用于根组件中的 App 级配置;
  • componentDidMount:在第一次渲染之后执行,能够在这里做AJAX申请,DOM的操作或状态更新以及设置事件监听器;
  • componentWillReceiveProps:在初始化render的时候不会执行,它会在组件承受到新的状态(Props)时被触发,个别用于父组件状态更新时子组件的从新渲染
  • shouldComponentUpdate:确定是否更新组件。默认状况下,它返回true。如果确定在state或props更新后组件不须要在从新渲染,则能够返回false,这是一个进步性能的办法;
  • componentWillUpdate:在shouldComponentUpdate返回true确定要更新组件之前件之前执行;
  • componentDidUpdate:它次要用于更新DOM以响应props或state更改;
  • componentWillUnmount:它用于勾销任何的网络申请,或删除与组件关联的所有事件监听器。

4、setState到底是异步还是同步?

先给出答案: 有时体现出异步,有时体现出同步。

  • setState只在合成事件和钩⼦函数中是“异步”的,在原⽣事件和setTimeout中都是同步的;
  • setState的“异步”并不是说外部由异步代码实现,其实自身执⾏的过程和代码都是同步的,只是合成事件和钩⼦函数的调⽤程序在更新之前,导致在合成事件和钩⼦函数中没法⽴⻢拿到更新后的值,造成了所谓的“异步”,当然能够通过第⼆个参数setState(partialState, callback)中的callback拿到更新后的后果;
  • setState的批量更新优化也是建⽴在“异步”(合成事件、钩⼦函数)之上的,在原⽣事件和setTimeout中不会批量更新,在“异步”中如果对同⼀个值进⾏屡次 setState,setState的批量更新策略会对其进⾏笼罩,取最初⼀次的执⾏,如果是同时setState多个不同的值,在更新时会对其进⾏合并批量更新。

5、React中keys的作用是什么?

render () {  return (    <ul>      {this.state.todoItems.map(({item,i}) => {        return <li key={i}>{item}</li>      })}    </ul>  )}复制代码

在React Diff算法中React会借助元素的Key值来判断该元素是早先创立的还是被挪动而来的元素,从而缩小不必要的元素重渲染。

6、受控组件和非受控组件区别是啥?

  • 受控组件是React管制中的组件,并且是表单数据实在的惟一起源。
  • 非受控组件是由DOM解决表单数据的中央,而不是在 React 组件中。

只管非受控组件通常更易于实现,因为只需应用refs即可从DOM中获取值,但通常倡议优先选择受管制的组件,而不是非受管制的组件。

这样做的次要起因是受控组件反对即时字段验证,容许有条件地禁用/启用按钮,强制输出格局。

7、如何防止组件的从新渲染?

React中最常见的问题之一是组件不必要地从新渲染。React提供了两个办法,在这些状况下十分有用:

  • React.memo():这能够避免不必要地从新渲染函数组件;
  • PureComponent:这能够避免不必要地从新渲染类组件。

这两种办法都依赖于对传递给组件的props的浅比拟,如果props没有扭转,那么组件将不会从新渲染。尽管这两种工具都十分有用,然而浅比拟会带来额定的性能损失,因而如果使用不当,这两种办法都会对性能产生负面影响。

通过应用React Profiler,能够在应用这些办法前后对性能进行测量,从而确保通过进行给定的更改来理论改良性能。

8、讲下redux的⼯作流程?

⾸先,咱们看下⼏个核⼼概念:

  • Store:保留数据的地⽅,你能够把它看成⼀个容器,整个应⽤只能有⼀个Store;
  • State:Store对象蕴含所有数据,如果想得到某个时点的数据,就要对Store⽣成快照,这种时点的数据汇合,就叫State;
  • Action: State的变动, 会导致View的变动。然而,⽤户接触不到State,只能接触到View。所以,State的变动必须是View导致的。Action就是View收回的告诉,示意State应该要发⽣变动了;
  • Action Creator:View要发送多少种音讯,就会有多少种Action。如果都⼿写,会很麻烦,所以咱们定义⼀个函数来⽣成Action,这个函数就叫Action Creator;
  • Reducer:Store收到Action当前,必须给出⼀个新的State,这样View才会发⽣变动。这种State的计算过程就叫做Reducer。Reducer是⼀个函数,它承受Action和以后State作为参数,返回⼀个新的State;
  • dispatch:是View收回Action的唯⼀⽅法。

而后咱们过下整个⼯作流程:

  1. ⾸先,⽤户(通过View)收回Action,收回⽅式就⽤到了dispatch⽅法;
  2. 而后,Store⾃动调⽤Reducer,并且传⼊两个参数:以后State和收到的Action,Reducer会返回新的State;
  3. State⼀旦有变动,Store就会调⽤监听函数,来更新View。

到这⼉为⽌,⼀次⽤户交互流程完结。能够看到,在整个流程中数据都是单向流动的,这种⽅式保障了流程的清晰。

9、redux与mobx的区别?

两者对⽐:

  • redux将数据保留在单⼀的store中,mobx将数据保留在扩散的多个store中
  • redux使⽤plain object保留数据,须要⼿动解决变动后的操作;mobx适⽤observable保留数据,数据变动后⾃动解决响应的操作
  • redux使⽤不可变状态,这意味着状态是只读的,不能间接去批改它,⽽是应该返回⼀个新的状态,同时使⽤纯函数;mobx中的状态是可变的,能够间接对其进⾏批改

mobx相对来说⽐较简略,在其中有很多的形象,mobx更多的使⽤⾯向对象的编程思维;redux会⽐较简单,因为其中的函数式编程思维把握起来不是那么容易,同时须要借助⼀系列的中间件来解决异步和副作⽤

  • mobx中有更多的形象和封装,调试会⽐较艰难,同时后果也难以预测;⽽redux提供可能进⾏工夫回溯的开发⼯具,同时其纯函数以及更少的形象,让调试变得更加的容易

场景辨析:

  • 基于以上区别,咱们能够简略得剖析⼀下两者的不同使⽤场景。
  • mobx更适宜数据不简单的应⽤:mobx难以调试,很多状态⽆法回溯,⾯对复杂度⾼的应⽤时,往往⼒不从⼼。
  • redux适宜有回溯需要的应⽤:⽐如⼀个画板应⽤、⼀个表格应⽤,很多时候须要撤销、重做等操作,因为redux不可变的个性,人造⽀持这些操作。
  • mobx适宜短平快的项⽬:mobx上⼿简略,样板代码少,能够很⼤水平上提⾼开发效率。
  • 当然mobx和redux也并不⼀定是⾮此即彼的关系,你也能够在项⽬中⽤redux作为全局状态治理,⽤mobx作为组件部分状态管理器来⽤。

10、redux异步中间件之间的优劣?

redux-thunk长处:

  • 体积⼩:redux-thunk的实现⽅式很简略,只有不到20⾏代码;
  • 使⽤简略:redux-thunk没有引⼊像redux-saga或者redux-observable额定的范式,上⼿简略。

redux-thunk缺点:

  • 样板代码过多:与redux自身⼀样,通常⼀个申请须要⼤量的代码,⽽且很多都是反复性质的;
  • 耦合重大:异步操作与redux的action偶合在⼀起,不⽅便治理;
  • 性能孱弱:有⼀些理论开发中常⽤的性能须要⾃⼰进⾏封装。

redux-saga长处:

  • 异步解耦:异步操作被被转移到独自saga.js中,不再是掺杂在action.js或component.js中;
  • action解脱thunk function: dispatch的参数仍然是⼀个纯正的 action (FSA),⽽不是充斥 “⿊魔法” thunk function;
  • 异样解决:受害于 generator function 的saga实现,代码异样/申请失败都能够间接通过try/catch语法间接捕捉解决;
  • 性能强⼤:redux-saga提供了⼤量的Saga辅助函数和Effect创立器供开发者使⽤,开发者⽆须封装或者简略封装即可使⽤;
  • 灵便:redux-saga能够将多个Saga能够串⾏/并⾏组合起来,造成⼀个⾮常实⽤的异步flow;
  • 易测试,提供了各种case的测试⽅案,包含mock task,分⽀笼罩等等。

redux-saga缺点:

  • 额定的学习老本:redux-saga不仅在使⽤难以了解的generator function,⽽且无数⼗个API,学习老本远超reduxthunk,最重要的是你的额定学习老本是只服务于这个库的,与redux-observable不同,redux-observable尽管也有额定学习老本然而背地是rxjs和⼀整套思维;
  • 体积庞⼤:体积略⼤,代码近2000⾏,min版25KB左右;
  • 性能过剩:实际上并发管制等性能很难⽤到,然而咱们仍然须要引⼊这些代码;
  • ts⽀持不敌对:yield⽆法返回TS类型。

redux-observable长处:

  • 性能最强:因为背靠rxjs这个强⼤的响应式编程的库,借助rxjs的操作符,你能够⼏乎做任何你能想到的异步解决;
  • 背靠rxjs:因为有rxjs的加持,如果你曾经学习了rxjs,redux-observable的学习老本并不⾼,⽽且随着rxjs的降级reduxobservable也会变得更强⼤。

redux-observable缺点:

  • 学习老本奇⾼:如果你不会rxjs,则须要额定学习两个简单的库;
  • 社区⼀般:redux-observable的下载量只有redux-saga的1/5,社区也不够沉闷,在简单异步流中间件这个层⾯reduxsaga仍处于领导位置。