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 是什么
- JSX 是一种 JavaScript 的语法扩大(eXtension),也在很多中央称之为 JavaScript XML,因为看起就是一段 XML 语法;
- 它用于形容咱们的 UI 界面,并且其实现能够和 JavaScript 交融在一起应用;
- 它不同于 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 的唯⼀⽅法。
而后咱们过下整个⼯作流程:
- ⾸先,⽤户(通过 View)收回 Action,收回⽅式就⽤到了 dispatch ⽅法;
- 而后,Store ⾃动调⽤ Reducer,并且传⼊两个参数:以后 State 和收到的 Action,Reducer 会返回新的 State;
- 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 仍处于领导位置。