阿里前端二面常考react面试题(必备)

本文深入探讨了React组件开发中的作用域问题,包括ES5和ES6的区别,以及如何处理事件。文章还详细解释了React的虚拟DOM和Diff算法的实现原理,强调了强制刷新的场景以及`componentDidMount`中处理AJAX请求的时机。此外,还介绍了React组件的state和props的区别,以及Redux在状态管理中的作用。
摘要由CSDN通过智能技术生成

说说 React组件开发中关于作用域的常见问题。

在 EMAScript5语法规范中,关于作用域的常见问题如下。
(1)在map等方法的回调函数中,要绑定作用域this(通过bind方法)。
(2)父组件传递给子组件方法的作用域是父组件实例化对象,无法改变。
(3)组件事件回调函数方法的作用域是组件实例化对象(绑定父组件提供的方法就是父组件实例化对象),无法改变。
在 EMAScript6语法规范中,关于作用域的常见问题如下。
(1)当使用箭头函数作为map等方法的回调函数时,箭头函数的作用域是当前组件的实例化对象(即箭头函数的作用域是定义时的作用域),无须绑定作用域。
(2)事件回调函数要绑定组件作用域。
(3)父组件传递方法要绑定父组件作用域。
总之,在 EMAScript6语法规范中,组件方法的作用域是可以改变的。

描述事件在 React中的处理方式。

为了解决跨浏览器兼容性问题, React中的事件处理程序将传递 SyntheticEvent的实例,它是跨浏览器事件的包装器。这些 SyntheticEvent与你习惯的原生事件具有相同的接口,它们在所有浏览器中都兼容。
React实际上并没有将事件附加到子节点本身。而是通过事件委托模式,使用单个事件监听器监听顶层的所有事件。这对于性能是有好处的。这也意味着在更新DOM时, React不需要担心跟踪事件监听器。

react 的虚拟dom是怎么实现的

首先说说为什么要使用Virturl DOM,因为操作真实DOM的耗费的性能代价太高,所以react内部使用js实现了一套dom结构,在每次操作在和真实dom之前,使用实现好的diff算法,对虚拟dom进行比较,递归找出有变化的dom节点,然后对其进行更新操作。为了实现虚拟DOM,我们需要把每一种节点类型抽象成对象,每一种节点类型有自己的属性,也就是prop,每次进行diff的时候,react会先比较该节点类型,假如节点类型不一样,那么react会直接删除该节点,然后直接创建新的节点插入到其中,假如节点类型一样,那么会比较prop是否有更新,假如有prop不一样,那么react会判定该节点有更新,那么重渲染该节点,然后在对其子节点进行比较,一层一层往下,直到没有子节点

React的虚拟DOM和Diff算法的内部实现

传统 diff 算法的时间复杂度是 O(n^3),这在前端 render 中是不可接受的。为了降低时间复杂度,react 的 diff 算法做了一些妥协,放弃了最优解,最终将时间复杂度降低到了 O(n)。

那么 react diff 算法做了哪些妥协呢?,参考如下:

  1. tree diff:只对比同一层的 dom 节点,忽略 dom 节点的跨层级移动

如下图,react 只会对相同颜色方框内的 DOM 节点进行比较,即同一个父节点下的所有子节点。当发现节点不存在时,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。

这样只需要对树进行一次遍历,便能完成整个 DOM 树的比较。

image-20210302195610674

这就意味着,如果 dom 节点发生了跨层级移动,react 会删除旧的节点,生成新的节点,而不会复用。

  1. component diff:如果不是同一类型的组件,会删除旧的组件,创建新的组件

image-20210302195654736

  1. element diff:对于同一层级的一组子节点,需要通过唯一 id 进行来区分
  • 如果没有 id 来进行区分,一旦有插入动作,会导致插入位置之后的列表全部重新渲染
  • 这也是为什么渲染列表时为什么要使用唯一的 key。

react 强制刷新

component.forceUpdate() 一个不常用的生命周期方法, 它的作用就是强制刷新

官网解释如下

默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。

调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。如果标记发生变化,React 仍将只更新 DOM。

通常你应该避免使用 forceUpdate(),尽量在 render() 中使用 this.props 和 this.state。

shouldComponentUpdate 在初始化 和 forceUpdate 不会执行

React 16.X 中 props 改变后在哪个生命周期中处理

在getDerivedStateFromProps中进行处理。

这个生命周期函数是为了替代componentWillReceiveProps存在的,所以在需要使用componentWillReceiveProps时,就可以考虑使用getDerivedStateFromProps来进行替代。

两者的参数是不相同的,而getDerivedStateFromProps是一个静态函数,也就是这个函数不能通过this访问到class的属性,也并不推荐直接访问属性。而是应该通过参数提供的nextProps以及prevState来进行判断,根据新传入的props来映射到state。

需要注意的是,如果props传入的内容不需要影响到你的state,那么就需要返回一个null,这个返回值是必须的,所以尽量将其写到函数的末尾:

static getDerivedStateFromProps(nextProps, prevState) {
   
    const {
   type} = nextProps;
    // 当传入的type发生变化的时候,更新state
    if (type !== prevState.type) {
   
        return {
   
            type,
        };
    }
    // 否则,对于state不进行任何操作
    return null
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值