11 道高频 React 面试题及详解, 另附有 React 面试题集合
为什么选择使用框架而不是原生?
框架的好处:
1.组件化: 其中以 React 的组件化最为彻底,甚至可以到函数级别的原子组件,高度的组件化可以是我们的工程易于维护、易于组合拓展。
2.天然分层: JQuery`时代的代码大部分情况下是面条代码,耦合严重,现代框架不管是 MVC、MVP 还是 MVVM 模式都能帮助我们进行分层,代码解耦更易于读写。
3.生态: 现在主流前端框架都自带生态,不管是数据流管理架构还是 UI 库都有成熟的解决方案。
4.开发效率: 现代前端框架都默认自动更新 DOM,而非我们手动操作,解放了开发者的手动 DOM 成本,提高开发效率,从根本上解决了 UI 与状态同步问题.
虚拟 DOM 的优劣如何?
优点:
保证性能下限: 虚拟 DOM 可以经过 diff 找出最小差异,然后批量进行 patch,这种操作虽然比不上手动优化,但是比起粗暴的 DOM 操作性能要好很多,因此虚拟 DOM 可以保证性能下限
无需手动操作 DOM: 虚拟 DOM 的 diff 和 patch 都是在一次更新中自动进行的,我们无需手动操作 DOM,极大提高开发效率
跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、移动端开发等等
缺点:
无法进行极致优化: 在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化,比如 VScode 采用直接手动操作 DOM 的方式进行极端的性能优化
虚拟 DOM 实现原理?
虚拟 DOM 本质上是 JavaScript 对象,是对真实 DOM 的抽象
状态变更时,记录新树和旧树的差异
最后把差异更新到真正的 dom 中
React 的请求应该放在哪个生命周期中?
React 的异步请求到底应该放在哪个生命周期里,有人认为在 componentWillMount 中可以提前进行异步请求,避免白屏,其实这个观点是有问题的.
由于 JavaScript 中异步事件的性质,当您启动 API 调用时,浏览器会在此期间返回执行其他工作。当 React 渲染一个组件时,它不会等待 componentWillMount 它完成任何事情 - React 继续前进并继续 render,没有办法“暂停”渲染以等待数据到达。
而且在 componentWillMount 请求会有一系列潜在的问题,首先,在服务器渲染时,如果在 componentWillMount 里获取数据,fetch data 会执行两次,一次在服务端一次在客户端,这造成了多余的请求,其次,在 React 16 进行 React Fiber 重写后,componentWillMount 可能在一次渲染中多次调用.
目前官方推荐的异步请求是在 componentDidmount 中进行.
如果有特殊需求需要提前请求,也可以在特殊情况下在 constructor 中请求:
setState 到底是异步还是同步?
先给出答案: 有时表现出异步,有时表现出同步
1.setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。
2.setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的 callback 拿到更新后的结果。
3.setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和 setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState,setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。
React 组件通信如何实现?
React 组件间通信方式:
父组件向子组件通讯: 父组件可以向子组件通过传 props 的方式,向子组件进行通讯
子组件向父组件通讯: props+回调的方式,父组件向子组件传递 props 进行通讯,此 props 为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到父组件的作用域中
兄弟组件通信: 找到这两个兄弟节点共同的父节点,结合上面两种方式由父节点转发信息进行通信
跨层级通信: Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言,对于跨越多层的全局数据通过 Context 通信再适合不过
发布订阅模式: 发布者发布事件,订阅者监听事件并做出反应,我们可以通过引入 event 模块进行通信- 全局状态管理工具: 借助 Redux 或者 Mobx 等全局状态管理工具进行通信,这种工具会维护一个全局状态中心 Store,并根据不同的事件产生新的状态
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。
到这儿为止,一次用户交互流程结束。可以看到,在整个流程中数据都是单向流动的,这种方式保证了流程的清晰。
react-redux 是如何工作的?
Provider: Provider 的作用是从最外部封装了整个应用,并向 connect 模块传递 store
connect: 负责连接 React 和 Redux
获取 state: connect 通过 context 获取 Provider 中的 store,通过 store.getState()获取整个 store tree 上所有 state
包装原组件: 将 state 和 action 通过 props 的方式传入到原组件内部 wrapWithConnect 返回一个 ReactComponent 对象 Connect,Connect 重新 render 外部传入的原组件 WrappedComponent,并把 connect 中传入的 mapStateToProps, mapDispatchToProps 与组件上原有的 props 合并后,通过属性的方式传给 WrappedComponent
监听 store tree 变化: connect 缓存了 store tree 中 state 的状态,通过当前 state 状态和变更前 state 状态进行比较,从而确定是否调用 this.setState()方法触发 Connect 及其子组件的重新渲染
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 作为组件局部状态管理器来用.
redux 中如何进行异步操作?
当然,我们可以在`componentDidmount 中直接进行请求无须借助 redux.
但是在一定规模的项目中,上述方法很难进行异步流的管理,通常情况下我们会借助 redux 的异步中间件进行异步处理.
redux 异步流中间件其实有很多,但是当下主流的异步中间件只有两种 redux-thunk、redux-saga,当然 redux-observable 可能也有资格占据一席之地,其余的异步中间件不管是社区活跃度还是 npm 下载量都比较差了。
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,学习成本远超 redux-thunk,最重要的是你的额外学习成本是只服务于这个库的,与 redux-observable 不同,redux-observable 虽然也有额外学习成本但是背后是 rxjs 和一整套思想
体积庞大: 体积略大,代码近 2000 行,min 版 25KB 左右
功能过剩: 实际上并发控制等功能很难用到,但是我们依然需要引入这些代码
ts 支持不友好: yield 无法返回 TS 类型
redux-observable 优点:
功能最强: 由于背靠 rxjs 这个强大的响应式编程的库,借助 rxjs 的操作符,你可以几乎做任何你能想到的异步处理
背靠 rxjs: 由于有 rxjs 的加持,如果你已经学习了 rxjs,redux-observable 的学习成本并不高,而且随着 rxjs 的升级 redux-observable 也会变得更强大
redux-observable 缺陷:
学习成本奇高: 如果你不会 rxjs,则需要额外学习两个复杂的库
社区一般: redux-observable 的下载量只有 redux-saga 的 1/5,社区也不够活跃,在复杂异步流中间件这个层面 redux-saga 仍处于领导地位
React 面试题集合
面试光看这 11 道题怎么够呢?小编把 React 面试题整理成了一个集合,不多但经典哦。
基本知识
区分 Real DOM 和 Virtual DOM
什么是 React?
React 有什么特点?
列出 React 的一些主要优点。
React 有哪些限制?
什么是 JSX?###React 组件
你理解“在 React 中,一切都是组件”这句话。
解释 React 中 render() 的目的。
如何将两个或多个组件嵌入到一个组件中?
什么是 Props?
React 中的状态是什么?它是如何使用的?
区分状态和 props
React Redux
MVC 框架的主要问题是什么?
解释一下 Flux
什么是 Redux?
Redux 遵循的三个原则是什么?
你对“单一事实来源”有什么理解?
列出 Redux 的组件。
React 路由
什么是 React 路由?
为什么 React Router v4 中使用 switch 关键字 ?
为什么需要 React 中的路由?
列出 React Router 的优点。
React Router 与常规路由有何不同?
完整版的 React 面试题集合 PDF 资料直接点击这里就可以领取了哦。整理不易,还请点赞评论支持小编,给小编充充能量,谢谢!
评论