React面试指南

Reac知识图谱react

1、React基础使用

1. React中数据通讯有哪些方式

  • 简单层级传递,如父子,可使用props。算法

    <Child title="数据"/>
    复制代码
  • 祖先与子孙,跨层级数据传递或者兄弟组件通讯:Context、第三方状态管理库如redux、mobx等。redux

2. 如何使用跨层级数据传递

  • 建立Context对象
const TheContext = React.createContext();
复制代码
  • 使用Context Provider传递value
<TheContext.Provider>
	<Child/>
</TheContext.Provider>
复制代码
  • Provider的子孙组件消费value:contextType(只能用在类组件中且只能订阅单一context来源)、useContext(hook函数,只能用在函数组件或者自定义hook中)、Consumer。
//contextType
class Child extends Component {
  contextType = TheContext;
  componentDidMount() {
    console.log(this.context); //sy-log
  }
  render() {
    return <div>呵呵呵</div>;
  }
}
//useContext
function Child(props) {
  const context = useContext(TheContext);
  console.log(context); //sy-log
  return <div>哈哈哈</div>;
}
//Consumer 函数类组件均可
function Child(props) {
  return (
    <div> <TheContext.Consumer> {(context) => { console.log(context); //sy-log return <div>嗯嗯嗯</div>; }} </TheContext.Consumer> </div>
  );
}
复制代码

3. 类组件中的setState如何使用

setState(updater, [callback]);
复制代码

update:object | function。若是是object,则会与类组件中上次的state对象合并,若是是函数,(prevState, nextProps)=>{ return newState };数组

callback:可选,回调函数。markdown

类组件中的setState是批量更新,即咱们常说的异步。可是在原生事件和setTimeout中是同步的。react-router

2、React原理

1. key值有什么用?

key标记了节点在当前层级下的惟一性,和组件类型一块儿用于diff时候判断节点是否能够复用、是否要删除、是否要新增。dom

2. setState是同步仍是异步

有时表现出异步,有时表现出同步。异步

  • setState在合成事件和钩子函数中是异步的,在原生事件和 setTimeout 中是同步的。
  • 这里的异步并非说setState内部由异步代码实现,而是指setState的更新是批量更新,也就是说合成事件和钩子函数是在state更新以前就调用了,致使没法当即取到state更新以后的值,固然若是你须要再state更新以后作某些操做,则可使用setState(partialState, callback)的callback参数。
  • setState在原生事件中是同步的,主要是由于React源码没法肯定原生事件是何时注册的,不像合成事件,组件渲染的时候就能够经过合成事件的映射表得知。
  • 而若是setState定义在setTimeout中,因为setTimeout自己就是异步,就算是合成事件,等setTimeout里的setState要执行的时候,批量更新的标记也已经失效了,所以表现出来的依然是同步。

3. 什么fiber

fiber在React源码中表现为一个节点对象,仍然是虚拟dom,表现为单链表结构。其中child属性是第一个子fiber节点,sibling是下一个兄弟节点。ide

  • 在React16以前,React组件的子组件是一个children数组,而这些子组件的递归渲染只和children数组中的下标位置相关。
  • 对于大型项目来讲,组件树会很是大,那么递归遍历也就会很是耗时耗力,这个时候一些较高优先级的任务,如动画任务、和用户交互的任务(如input的onChange)等就应该被早点执行,否则用户可能就会看到卡顿的现象,这对用户体验是极其不利的。
  • 为了要解决上面的问题,能够给不一样的任务添加优先级。要作到这一点,首先节点的颗粒度也要够小,这就是后来出现的fiber节点。
  • 再者,若是一个任务a正在执行,可是这个时候来了更高优先级的任务b,那就要中断a,去执行b。也就是说,任务是须要可中断的。而且,被迫中断的a并非要被抛弃掉,可能执行完b之后仍是要再执行a的,那这个时候就须要a和b之间有个指针关系,否则执行完b了,怎么能找到a呢?因此fiber是个单链表结构。

4. 说说react中的diff

算法复杂度:O(n)函数

React中这个diff算法复杂度的前提是:深度优先遍历、同级比较、只有key值和类型彻底相同的组件才能够复用。

接下来如下图为例,来讲一下React diff的流程:

image-20191022194524132

假设上面的树为老的虚拟dom节点,下面的树为新的虚拟dom节点,圆形和多边形节点标识不一样的组件类型,大写字母标识节点的key。

  • 按照深度优先遍历,先A再B,而后D,可是两个新老树里D组件类型不一样,老E和新D的key不一样,都没法复用,所以新增新D。
  • 新的D节点没有子节点,所以下一步是G节点。虽然老树里有G节点,可是和新树里的G节点不是同一层级,所以没法复用。所以新G须要新增。
  • 这样新树B节点下的DG都须要新增,老树下的DE都须要被删除。
  • 新树的G节点没有子节点和兄弟节点,而后经过G的爸爸B节点找到叔叔C节点,新老树下都有C节点,而且同一层级下,能够复用,虽然相对位置不一样,可是不要紧能够移动位置。
  • 老C下有G,新C的没有,则老树的C须要被删除。
  • 新C没有子节点,下一步是兄弟H节点,这个时候新老H的key和组件类型都相同,仍是同一层级下,所以复用就能够了。
  • OVER。

3、状态管理库

React知识图谱

1. 为何要使用状态管理库

目前任何一个状态管理库都不是强制使用的,也有不少精小的项目不使用第三方状态管理库,而只是使用React自身的state、useContext等API就能够达到目的。固然,对于大型项目,仍是建议使用一个状态管理库,毕竟项目越大,须要管理、共享的状态越多,这个时候为了不data层与view层变成一锅粥,仍是使用个状态管理库吧。

2. React目前常见的状态管理库有哪些,比较一下

redux、mobx、recoil(实验阶段)。

  • redux是集中式管理state,而recoil和mobx都是分散式。
  • recoil中状态的读写都是Hooks函数,目前没有提供类组件的使用方式。
  • recoil是Facebook开发的,可使用React内部的调度机制,这是redux和mobx不支持的。
  • recoil目前仍是实验阶段,想要应用到的本身的项目中,等待正式版发了再说吧。

3. redux如何实现异步

redux自己是不支持异步的,可使用中间件,redux-thunk、redux-saga。

4、路由管理库

1. Route渲染组件有哪些方式?

Route有三种互斥的组件渲染方式,按照优先级高低分别是children、component、render。

2. Route渲染组件的三种方式,有什么不一样?

children是不论是否匹配都会渲染,而component和render都是匹配了才会渲染。另外,children和render的参数是函数,而component的参数是React组件。

当你用component的时候,Route会用你指定的组件和React.createElement建立一个新的[React element]。这意味着当你提供的是一个内联函数的时候,每次render都会建立一个新的组件。这会致使再也不更新已经现有组件,而是直接卸载而后再去挂载一个新的组件。所以,当用到内联函数的内联渲染时,请使用render或者children。

react-router中Route的render源码以下:

image-20200224174023810

相关文章
相关标签/搜索