前端科举八股文-REACT篇
- vue和react有和异同?
- useEffect中为什么不能使用异步函数?
- useEffect和useLayoutEffect的区别
- react的生命周期?
- state和props的区别? 讲讲你的理解?
- 受控组件和非受控组件的区别
- 讲一下你理解的react事件机制?
- 为什么react16之后不把事件挂载到document之后了?
- 讲一下react的HOC
- HOC可以用来做什么?
- 讲讲你对react fiber的理解?
- 讲讲react.component和react.pureComponents的区别
- 讲一讲react的HOC?
- 哪些操作会触发react的重新渲染,rerender的过程中会发生什么?
- 如何理解react的hooks
- hooks的使用限制?
- react的性能优化方式?
- react中的jsx转换成真实Dom的过程?
- react项目中如何进行错误捕获?
- 讲讲你对setState的理解(包括同步异步、执行机制)
vue和react有和异同?
相同点:
1、首先两个库都把主要的功能放在核心库,其他的附加功能可以交给第三方库,比如状态管理,路由管理,UI组件库等等
2、两个框架都有自己的脚手架工具,都可以很方便的搭建最佳实践项目
3、两个框架都使用了diff算法和虚拟dom来提高渲染效率
4、两个框架都提倡组件化开发项目
不同点
1、Vue中的双向绑定可以通过api来实现(v-modal),但是在react中需要手动实现双向绑定,比如在数据变化的时候去重新setState值。
2、在改变数据时,Vue会精准的更新状态值影响的组件,而react会更新当前组件以及它所有的子组件
3、实现响应式的方式不同,vue是通过劫持了数据的get和set方法,在set数据时去重新render视图。react组件是通过setState里面去调用更新视图的方法从而更新视图
useEffect中为什么不能使用异步函数?
1、useEffect中返回的函数需要在组件销毁时被调用,所以react需要在执行时就拿到这个返回值才能确定组件销毁时应该调用什么。
2、hooks执行有一个潜在逻辑,第二个useEffect执行必须等第一个执行完成之后才会执行,如果里面嵌套异步函数的话会使react组件的状态变化变得特别复杂且难以管理
useEffect和useLayoutEffect的区别
大多数情况下useEffect可以平替useLayoutEffect,只有某些时候需要计算组件元素布局的高宽时才需要使用到useLayoutEffect。useEffect是dom更新并且挂载到页面之后异步执行的。useLayoutEffect是在dom更新后,挂载到页面之前同步更新的。会阻塞页面的渲染(所以要慎用)。
react的生命周期?
可以根据react组件的生命周期给react分成三个不同的阶段。
// 组件挂载
constructor -> getDerivedStateFromProps -> render -> componentDidMount
// 组件更新
getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentdidupdate
// 组件卸载
componentWillUnmounted
介绍一个不太常用的周期getDerivedStateFromProps,这个hook在每次挂载和更新时都会调用,他是组件的实例方法,因此不能获取组件的this实例,他接受的参数是即将更新的props和未更新的state。他的返回值将作为组件最新的state来使用,可以结合shouldComponentUpdate来实现避免组件不必要的更新。
state和props的区别? 讲讲你的理解?
react的设计思想就是 UI= render(state),其中的这个state就是每个组件内部的状态数据,每个组件的视图都是根据这个状态数据来渲染的。而同时react又有组件化思想,有些组件可能依赖外部比如其他组件的数据,那么这些「传入」的数据就是props
受控组件和非受控组件的区别
顾名思义,受控组件就是受状态控制的组件,比如组件的input的value值绑定了一个state,然后state变化时,input的value值同步发生改变,非受控组件一般是指组件的初始化值受传入的值控制,但是在内部维护自己的状态,需要获取最新的值时需要通过ref来定位到dom来取值。
讲一下你理解的react事件机制?
react的jsx上绑定的所有以on开头的事件机制实际上都是react内部实现的。实现原理是将所有的事件统一冒泡到一个根元素上进行统一处理,在react16之前是document,在16之后是每个jsx的根结点上。
这样做的好处是不必在每个jsx节点上去处理事件,而是统一管理,大大的提升了性能。其二是因为不同浏览器对事件的处理方式是不同的,而react对事件进行统一处理,磨平了不同浏览器之间的差异对开发者更加友好。
为什么react16之后不把事件挂载到document之后了?
因为在项目中只有一个document,16之后把事件挂载到根节点上,不同组件的根结点肯定是不同的,这样可以使不同版本的react应用可以共存于一个页面而不会有冲突。更利于微前端技术的应用。
讲一下react的HOC
hoc就是高阶组件,高阶函数就是接受一个函数为参数,返回一个功能更强大的函数的前端技术。相比于vue的话其实react是更容易实现高阶组件的,因为每一个react组件就是一个函数,而vue还需要借助mixin来实现。
HOC可以用来做什么?
可以做条件渲染,比如传入组件和控制显示的变量来控制组件是否显示。还可以做权限控制,传入受权限控制的组件和权限然后在内部根据权限来控制组件的展示。
讲讲你对react fiber的理解?
react和vue的diff机制不同,由于vue在响应式处理data的时候同时进行了依赖收集,所以vue可以在更新的时候精确的更新对应组件,而react不同,它在setState的时候必须同时更新当前组件以及所有的子组件,在v16之前没有fiber的时候这个更新的动作是同步的,会一直占用浏览器的资源直到完成这个动作为止,而如果项目很大的情况下卡顿的现象会很明显。而16版本出现的fiber,本质就是一个链表结构的虚拟dom,它结合了一个h5的api,可以在浏览器空闲时机去碎片化的完成这个更新的动作,每一次更新会从上次停止的地方继续,因为每一个fiber都准确的记录了当前节点的父节点,兄弟节点,子节点。方便react可以从断点去继续执行任务。
讲讲react.component和react.pureComponents的区别
react在更新组件的时候,会递归的更新当前组件和它所有的子组件,但是很多时候,更新它的子组件是没有必要的,所以在之前我们可以通过在react.shouldComponentUpdate中返回false去避免不必要的更新,react的pureComponent字面意思就是纯组件,本质就是官方实现了shouldComponentUpdate的react组件,但是它在比较引用对象类型的时候是浅比较,只会比较更新前后是否指向同一片内存区域,而不会比较里面的每一个值是否相等。
讲一讲react的HOC?
HOC就是高阶组件,和JS的高阶函数有点类似,高阶函数就是接受一个函数为参数,返回另一个功能更强大的函数,那所谓的高阶组件就是接受一个函数为参数的组件,而react实现高阶函数要比vue要方便的多,因为react组件的本质就是一个函数,可以很轻易的实现高阶组件,而vue要实现高阶函数要借助mixin的特性。
高阶函数往往应用在条件渲染,权限判断,强化state或props等场景。
哪些操作会触发react的重新渲染,rerender的过程中会发生什么?
react类组件中的setState和hooks中useState返回值的第二个参数来改变组件的状态值都会触发state更新,forceUpdate强制更新组件也会触发组件更新,还有根组件的reactDom.render,或者redux的dispatch操作。
在重新渲染时会比较更新前后的两个vdom,diff算法的具体流程是首先会比较两个树的根节点(fiberRoot),如果根节点不同那么则判断整个树需要更新。如果相同则会判断节点的属性以及子节点,对于同级节点,可以通过key来提高diff算法的效率,递归的比较所有子节点之后会根据每个节点的状态和变化情况生成一组记录对象,最后在更新的时候会遍历这个对象一次性更新所有的变更。
如何理解react的hooks
在react编写组件有两种方式,类组件和函数式组件,在类组件中我们可以很轻易的去通过生命周期,状态去实现功能,在hook
我们可以在react的类组件里面很方便的使用state来定义内部状态,通过生命周期来执行对应的逻辑,在函数式组件里面我们需要通过结合hooks来实现对应的功能,除此之外,hooks也方便我们更轻松的实现代码复用以及逻辑抽象。
hooks的使用限制?
1、只能在函数组件内使用
2、不能在条件、循环中使用
关于第一点,因为hooks本身就是为了使函数组件更灵活所诞生的一套API,所以它是基于函数组件设计的,自然也就只能在函数组件内部使用。
关于第二点,react内部是通过链表来顺序执行hooks,如果在条件或者循环中去定义hooks就会破坏hooks链表的有序性导致程序混乱难以管理。
react的性能优化方式?
1、可以从避免组件无效渲染的方向去优化,可以通过shouldComponentUpdate,pureComponent,react.memo来避免组件的无效重复渲染
2、可以使用一些性能优化的hooks,比如react的useMemo,useCallBack,useMemo是将一个值缓存起来,当依赖项不变时,缓存值不会重新计算,有点类似于Vue的computed,useCallback用法和useMemo差不多,但是缓存的是一个函数,可以将传入子组件的函数用useCallback缓存起来来避免不必要的重复渲染
3、在列表渲染时给每一个列表项加上key,可以提高diff算法的执行效率
4、由于每个jsx只能有一个根节点,为了避免很多无意义的div元素,可以使用fragement来包裹jsx元素。
5、组件懒加载(lazy)
6、服务端渲染(没用过)
react中的jsx转换成真实Dom的过程?
jsx首先会经过babel转译,最终会转译成react.creatElement的形式,节点类型大致可以分成四个类型,原生dom节点,文本节点,函数组件,类组件,然后react.creatElement会根据参数的不同执行不同的渲染逻辑。
react项目中如何进行错误捕获?
react提供了一个很成熟的方案去捕获在编码时导致应用崩溃的错误代码。也就是react16提出的错误边界概念。错误边界本质是一个react组件,可以在组件中使用getDerivedStateFromError和componentdidCatch两个生命周期来生成一个错误边界组件。之后就可以用错误边界组件来包裹需要容错的组件(一般是根组件)来进行错误捕获。
讲讲你对setState的理解(包括同步异步、执行机制)
同步异步?
setState在调用的时候是同步执行的,但是引发react的状态更新是异步的。原因是如果是同步更新状态的话那么每调用一次setState就会触发一次状态更新再触发组件的rerender,如果是异步的话就可以把一次多次setState的值合并之后统一去触发状态改变,视图更新。效率会更高
调用setState发生了什么?
首先会把setState的参数与组件当前的状态合并起来,触发所谓的“调和”过程。
然后根据合并之后的状态构建最新的vdom树,将新树和原树做对比比较出所有节点的变化情况统一存储到一个对象中,最后根据这个对象去触发最小话更新。
在延时器和原生dom事件中是同步还是异步?为什么?
setState在生命周期和react合成事件中表现为异步,在原生dom事件和延时器等异步api中表现为同步的。
在react底层源码中,有一个isBatchUpdates字段来控制是否是批量更新state,默认值是false,但是在生命周期和react合成事件调用前会把这个参数变成true,也就是在这两个hooks里面,setState需要批量更新state,也就是表现为异步。