前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React高频面试题(附答案)

React高频面试题(附答案)

原创
作者头像
flyzz177
发布2022-07-27 08:29:21
1.4K0
发布2022-07-27 08:29:21
举报

React面试题视频讲解:点击学习

key改了,会发生什么,会执行哪些周期函数?

在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性。

答:componentWillMount componentDidMount render

你对【单一数据源】有什么理解

redux使用 store将程序的整个状态存储在同一个地方,因此所有组件的状态都存储在 Store 中,并且它们从 Store 本身接收更新。单一状态树可以更容易地跟踪随时间的变化,并调试或检查程序

refs 是什么

  • refs是react中引用的简写,有主语存储特定 React 元素或组件的引用的属性,它将由组件渲染配置函数返回
  • 当我们需要输入框的内容,触发动画等时候可以使用refs

使用状态要注意哪些事情?

要注意以下几点。

  • 不要直接更新状态
  • 状态更新可能是异步的
  • 状态更新要合并。
  • 数据从上向下流动

组件通信的方式有哪些

  • ⽗组件向⼦组件通讯: ⽗组件可以向⼦组件通过传 props 的⽅式,向⼦组件进⾏通讯
  • ⼦组件向⽗组件通讯: props+回调的⽅式,⽗组件向⼦组件传递props进⾏通讯,此props为作⽤域为⽗组件⾃身的函 数,⼦组件调⽤该函数,将⼦组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中
  • 兄弟组件通信: 找到这两个兄弟节点共同的⽗节点,结合上⾯两种⽅式由⽗节点转发信息进⾏通信
  • 跨层级通信: Context 设计⽬的是为了共享那些对于⼀个组件树⽽⾔是“全局”的数据,例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过 Context 通信再适合不过
  • 发布订阅模式: 发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event模块进⾏通信
  • 全局状态管理⼯具: 借助Redux或者Mobx等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store,并根据不同的事件产⽣新的状态

state 和 props 触发更新的生命周期分别有什么区别?

state 更新流程:
函数:
  1. shouldComponentUpdate: 当组件的 state 或 props 发生改变时,都会首先触发这个生命周期函数。它会接收两个参数:nextProps, nextState——它们分别代表传入的新 props 和新的 state 值。拿到这两个值之后,我们就可以通过一些对比逻辑来决定是否有 re-render(重渲染)的必要了。如果该函数的返回值为 false,则生命周期终止,反之继续;

注意:此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。应该考虑使用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()

  1. componentWillUpdate:当组件的 state 或 props 发生改变时,会在渲染之前调用 componentWillUpdate。componentWillUpdate 是 React16 废弃的三个生命周期之一。过去,我们可能希望能在这个阶段去收集一些必要的信息(比如更新前的 DOM 信息等等),现在我们完全可以在 React16 的 getSnapshotBeforeUpdate 中去做这些事;
  2. componentDidUpdate:componentDidUpdate() 会在UI更新后会被立即调用。它接收 prevProps(上一次的 props 值)作为入参,也就是说在此处我们仍然可以进行 props 值对比(再次说明 componentWillUpdate 确实鸡肋哈)。

props 更新流程:
更新,props 更新后唯一的区别是增加了对 componentWillReceiveProps 的调用。关于 componentWillReceiveProps,需要知道这些事情:
  • componentWillReceiveProps:它在Component接受到新的 props 时被触发。componentWillReceiveProps 会接收一个名为 nextProps 的参数(对应新的 props 值)。该生命周期是 React16 废弃掉的三个生命周期之一。在它被废弃前,可以用它来比较 this.props 和 nextProps 来重新setState。在 React16 中,用一个类似的新生命周期 getDerivedStateFromProps 来代替它。

React中可以在render访问refs吗?为什么?

代码语言:javascript
复制
<>
  <span id="name" ref={this.spanRef}>{this.state.title}</span>
  <span>{     this.spanRef.current ? '有值' : '无值'  }</span>
</>
复制代码
不可以,render 阶段 DOM 还没有生成,无法获取 DOM。DOM 的获取需要在 pre-commit 阶段和 commit 阶段:
imagepng
imagepng

对 React-Intl 的理解,它的工作原理?

React-intl是雅虎的语言国际化开源项目FormatJS的一部分,通过其提供的组件和API可以与ReactJS绑定。

React-intl提供了两种使用方法,一种是引用React组件,另一种是直接调取API,官方更加推荐在React项目中使用前者,只有在无法使用React组件的地方,才应该调用框架提供的API。它提供了一系列的React组件,包括数字格式化、字符串格式化、日期格式化等。

在React-intl中,可以配置不同的语言包,他的工作原理就是根据需要,在语言包之间进行切换。

对有状态组件和无状态组件的理解及使用场景

(1)有状态组件

特点:

  • 是类组件
  • 有继承
  • 可以使用this
  • 可以使用react的生命周期
  • 使用较多,容易频繁触发生命周期钩子函数,影响性能
  • 内部使用 state,维护自身状态的变化,有状态组件根据外部组件传入的 props 和自身的 state进行渲染。

使用场景:

  • 需要使用到状态的。
  • 需要使用状态操作组件的(无状态组件的也可以实现新版本react hooks也可实现)

总结: 类组件可以维护自身的状态变量,即组件的 state ,类组件还有不同的生命周期方法,可以让开发者能够在组件的不同阶段(挂载、更新、卸载),对组件做更多的控制。类组件则既可以充当无状态组件,也可以充当有状态组件。当一个类组件不需要管理自身状态时,也可称为无状态组件。

(2)无状态组件 特点:

  • 不依赖自身的状态state
  • 可以是类组件或者函数组件。
  • 可以完全避免使用 this 关键字。(由于使用的是箭头函数事件无需绑定)
  • 有更高的性能。当不需要使用生命周期钩子时,应该首先使用无状态函数组件
  • 组件内部不维护 state ,只根据外部组件传入的 props 进行渲染的组件,当 props 改变时,组件重新渲染。

使用场景:

  • 组件不需要管理 state,纯展示

优点:

  • 简化代码、专注于 render
  • 组件不需要被实例化,无生命周期,提升性能。 输出(渲染)只取决于输入(属性),无副作用
  • 视图和数据的解耦分离

缺点:

  • 无法使用 ref
  • 无生命周期方法
  • 无法控制组件的重渲染,因为无法使用shouldComponentUpdate 方法,当组件接受到新的属性时则会重渲染

总结: 组件内部状态且与外部无关的组件,可以考虑用状态组件,这样状态树就不会过于复杂,易于理解和管理。当一个组件不需要管理自身状态时,也就是无状态组件,应该优先设计为函数组件。比如自定义的 <Button/><Input /> 等组件。

React组件的构造函数有什么作用?它是必须的吗?

构造函数主要用于两个目的:

  • 通过将对象分配给this.state来初始化本地状态
  • 将事件处理程序方法绑定到实例上

所以,当在React class中需要设置state的初始值或者绑定事件时,需要加上构造函数,官方Demo:

代码语言:javascript
复制
class LikeButton extends React.Component {
  constructor() {
    super();
    this.state = {
      liked: false
    };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({liked: !this.state.liked});
  }
  render() {
    const text = this.state.liked ? 'liked' : 'haven\'t liked';
    return (
      <div onClick={this.handleClick}>
        You {text} this. Click to toggle.      </div>
    );
  }
}
ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);
复制代码

构造函数用来新建父类的this对象;子类必须在constructor方法中调用super方法;否则新建实例时会报错;因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法;子类就得不到this对象。

注意:

  • constructor () 必须配上 super(), 如果要在constructor 内部使用 this.props 就要 传入props , 否则不用
  • JavaScript中的 bind 每次都会返回一个新的函数, 为了性能等考虑, 尽量在constructor中绑定事件

在React中组件的this.state和setState有什么区别?

this.state通常是用来初始化state的,this.setState是用来修改state值的。如果初始化了state之后再使用this.state,之前的state会被覆盖掉,如果使用this.setState,只会替换掉相应的state值。所以,如果想要修改state的值,就需要使用setState,而不能直接修改state,直接修改state之后页面是不会更新的。

当调用setState时,React render 是如何工作的?

咱们可以将"render"分为两个步骤:

  1. 虚拟 DOM 渲染:当render方法被调用时,它返回一个新的组件的虚拟 DOM 结构。当调用setState()时,render会被再次调用,因为默认情况下shouldComponentUpdate总是返回true,所以默认情况下 React 是没有优化的。
  2. 原生 DOM 渲染:React 只会在虚拟DOM中修改真实DOM节点,而且修改的次数非常少——这是很棒的React特性,它优化了真实DOM的变化,使React变得更快。

在React中如何避免不必要的render?

React 基于虚拟 DOM 和高效 Diff 算法的完美配合,实现了对 DOM 最小粒度的更新。大多数情况下,React 对 DOM 的渲染效率足以业务日常。但在个别复杂业务场景下,性能问题依然会困扰我们。此时需要采取一些措施来提升运行性能,其很重要的一个方向,就是避免不必要的渲染(Render)。这里提下优化的点:

  • shouldComponentUpdate 和 PureComponent

在 React 类组件中,可以利用 shouldComponentUpdate或者 PureComponent 来减少因父组件更新而触发子组件的 render,从而达到目的。shouldComponentUpdate 来决定是否组件是否重新渲染,如果不希望组件重新渲染,返回 false 即可。

  • 利用高阶组件

在函数组件中,并没有 shouldComponentUpdate 这个生命周期,可以利用高阶组件,封装一个类似 PureComponet 的功能

  • 使用 React.memo

React.memo 是 React 16.6 新的一个 API,用来缓存组件的渲染,避免不必要的更新,其实也是一个高阶组件,与 PureComponent 十分类似,但不同的是, React.memo只能用于函数组件。

在调用setState 之后发生了什么

  • 状态合并,触发调和:

setState函数之后,会将传入的参数对象与当前的状态合并,然后出发调用过程

  • 根据新的状态构建虚拟dom树

经过调和过程,react会高效的根据新的状态构建虚拟DOM树,准备渲染整个UI页面

  • 计算新老树节点差异,最小化渲染

得倒新的虚拟DOM树后,会计算出新老树的节点差异,会根据差异对界面进行最小化渲染

  • 按需更新

在差异话计算中,react可以相对准确的知道哪些位置发生了改变以及该如何改变,这保证按需更新,而不是宣布重新渲染

React的生命周期有哪些?

React 通常将组件生命周期分为三个阶段:

  • 装载阶段(Mount),组件第一次在DOM树中被渲染的过程;
  • 更新过程(Update),组件状态发生变化,重新更新渲染的过程;
  • 卸载过程(Unmount),组件从DOM树中被移除的过程;
imagepng
imagepng
1)组件挂载阶段

挂载阶段组件被创建,然后组件实例插入到 DOM 中,完成组件的第一次渲染,该过程只会发生一次,在此阶段会依次调用以下这些方法:

  • constructor
  • getDerivedStateFromProps
  • render
  • componentDidMount
(1)constructor

组件的构造函数,第一个被执行,若没有显式定义它,会有一个默认的构造函数,但是若显式定义了构造函数,我们必须在构造函数中执行 super(props),否则无法在构造函数中拿到this。

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数Constructor

constructor中通常只做两件事:

  • 初始化组件的 state
  • 给事件处理方法绑定 this
代码语言:javascript
复制
constructor(props) {
  super(props);
  // 不要在构造函数中调用 setState,可以直接给 state 设置初始值
  this.state = { counter: 0 }
  this.handleClick = this.handleClick.bind(this)
}
复制代码
(2)getDerivedStateFromProps
代码语言:javascript
复制
static getDerivedStateFromProps(props, state)
复制代码

这是个静态方法,所以不能在这个函数里使用 this,有两个参数 propsstate,分别指接收到的新参数和当前组件的 state 对象,这个函数会返回一个对象用来更新当前的 state 对象,如果不需要更新可以返回 null

该函数会在装载时,接收到新的 props 或者调用了 setStateforceUpdate 时被调用。如当接收到新的属性想修改 state ,就可以使用。

代码语言:javascript
复制
// 当 props.counter 变化时,赋值给 state 
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      counter: 0
    }
  }
  static getDerivedStateFromProps(props, state) {
    if (props.counter !== state.counter) {
      return {
        counter: props.counter
      }
    }
    return null
  }

  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1
    })
  }
  render() {
    return (
      <div>
        <h1 onClick={this.handleClick}>Hello, world!{this.state.counter}</h1>
      </div>
    )
  }
}
复制代码

现在可以显式传入 counter ,但是这里有个问题,如果想要通过点击实现 state.counter 的增加,但这时会发现值不会发生任何变化,一直保持 props 传进来的值。这是由于在 React 16.4^ 的版本中 setStateforceUpdate 也会触发这个生命周期,所以当组件内部 state 变化后,就会重新走这个方法,同时会把 state 值赋值为 props 的值。因此需要多加一个字段来记录之前的 props 值,这样就会解决上述问题。具体如下:

代码语言:javascript
复制
// 这里只列出需要变化的地方
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      // 增加一个 preCounter 来记录之前的 props 传来的值
      preCounter: 0,
      counter: 0
    }
  }
  static getDerivedStateFromProps(props, state) {
    // 跟 state.preCounter 进行比较
    if (props.counter !== state.preCounter) {
      return {
        counter: props.counter,
        preCounter: props.counter
      }
    }
    return null
  }
  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1
    })
  }
  render() {
    return (
      <div>
        <h1 onClick={this.handleClick}>Hello, world!{this.state.counter}</h1>
      </div>
    )
  }
}
复制代码
(3)render

render是React 中最核心的方法,一个组件中必须要有这个方法,它会根据状态 state 和属性 props 渲染组件。这个函数只做一件事,就是返回需要渲染的内容,所以不要在这个函数内做其他业务逻辑,通常调用该方法会返回以下类型中一个:

  • React 元素:这里包括原生的 DOM 以及 React 组件;
  • 数组和 Fragment(片段):可以返回多个元素;
  • Portals(插槽):可以将子元素渲染到不同的 DOM 子树种;
  • 字符串和数字:被渲染成 DOM 中的 text 节点;
  • 布尔值或 null:不渲染任何内容。
(4)componentDidMount()

componentDidMount()会在组件挂载后(插入 DOM 树中)立即调。该阶段通常进行以下操作:

  • 执行依赖于DOM的操作;
  • 发送网络请求;(官方建议)
  • 添加订阅消息(会在componentWillUnmount取消订阅);

如果在 componentDidMount 中调用 setState ,就会触发一次额外的渲染,多调用了一次 render 函数,由于它是在浏览器刷新屏幕前执行的,所以用户对此是没有感知的,但是我应当避免这样使用,这样会带来一定的性能问题,尽量是在 constructor 中初始化 state 对象。

在组件装载之后,将计数数字变为1:

代码语言:javascript
复制
class App extends React.Component  {
  constructor(props) {
    super(props)
    this.state = {
      counter: 0
    }
  }
  componentDidMount () {
    this.setState({
      counter: 1
    })
  }
  render ()  {
    return (
      <div className="counter">
        counter值: { this.state.counter }      </div>
    )
  }
}
复制代码
2)组件更新阶段

当组件的 props 改变了,或组件内部调用了 setState/forceUpdate,会触发更新重新渲染,这个过程可能会发生多次。这个阶段会依次调用下面这些方法:

  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • getSnapshotBeforeUpdate
  • componentDidUpdate
(1)shouldComponentUpdate
代码语言:javascript
复制
shouldComponentUpdate(nextProps, nextState)
复制代码

在说这个生命周期函数之前,来看两个问题:

  • setState 函数在任何情况下都会导致组件重新渲染吗?例如下面这种情况:
代码语言:javascript
复制
this.setState({number: this.state.number})
复制代码
  • 如果没有调用 setState,props 值也没有变化,是不是组件就不会重新渲染?

第一个问题答案是 ,第二个问题如果是父组件重新渲染时,不管传入的 props 有没有变化,都会引起子组件的重新渲染。

那么有没有什么方法解决在这两个场景下不让组件重新渲染进而提升性能呢?这个时候 shouldComponentUpdate 登场了,这个生命周期函数是用来提升速度的,它是在重新渲染组件开始前触发的,默认返回 true,可以比较 this.propsnextPropsthis.statenextState 值是否变化,来确认返回 true 或者 false。当返回 false 时,组件的更新过程停止,后续的 rendercomponentDidUpdate 也不会被调用。

注意: 添加 shouldComponentUpdate 方法时,不建议使用深度相等检查(如使用 JSON.stringify()),因为深比较效率很低,可能会比重新渲染组件效率还低。而且该方法维护比较困难,建议使用该方法会产生明显的性能提升时使用。

(2)getSnapshotBeforeUpdate
代码语言:javascript
复制
getSnapshotBeforeUpdate(prevProps, prevState)
复制代码

这个方法在 render 之后,componentDidUpdate 之前调用,有两个参数 prevPropsprevState,表示更新之前的 propsstate,这个函数必须要和 componentDidUpdate 一起使用,并且要有一个返回值,默认是 null,这个返回值作为第三个参数传给 componentDidUpdate

(3)componentDidUpdate

componentDidUpdate() 会在更新后会被立即调用,首次渲染不会执行此方法。 该阶段通常进行以下操作:

  • 当组件更新后,对 DOM 进行操作;
  • 如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求;(例如,当 props 未发生变化时,则不会执行网络请求)。
代码语言:javascript
复制
componentDidUpdate(prevProps, prevState, snapshot){}
复制代码

该方法有三个参数:

  • prevProps: 更新前的props
  • prevState: 更新前的state
  • snapshot: getSnapshotBeforeUpdate()生命周期的返回值
3)组件卸载阶段

卸载阶段只有一个生命周期函数,componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作:

  • 清除 timer,取消网络请求或清除
  • 取消在 componentDidMount() 中创建的订阅等;

这个生命周期在一个组件被卸载和销毁之前被调用,因此你不应该再这个方法中使用 setState,因为组件一旦被卸载,就不会再装载,也就不会重新渲染。

4)错误处理阶段

componentDidCatch(error, info),此生命周期在后代组件抛出错误后被调用。 它接收两个参数∶

  • error:抛出的错误。
  • info:带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息
React常见的生命周期如下:
imagepng
imagepng
生命周期的过程大致如下:
  • 挂载阶段,首先执行constructor构造方法,来创建组件
  • 创建完成之后,就会执行render方法,该方法会返回需要渲染的内容
  • 随后,React会将需要渲染的内容挂载到DOM树上
  • 挂载完成之后就会执行componentDidMount生命周期函数
  • 如果我们给组件创建一个props(用于组件通信)、调用setState(更改state中的数据)、调用forceUpdate(强制更新组件)时,都会重新调用render函数
  • render函数重新执行之后,就会重新进行DOM树的挂载
  • 挂载完成之后就会执行componentDidUpdate生命周期函数
  • 当移除组件时,就会执行componentWillUnmount生命周期函数

React主要生命周期总结:

  1. getDefaultProps:这个函数会在组件创建之前被调用一次(有且仅有一次),它被用来初始化组件的 Props;
  2. getInitialState:用于初始化组件的 state 值;
  3. componentWillMount:在组件创建后、render 之前,会走到 componentWillMount 阶段。这个阶段我个人一直没用过、非常鸡肋。后来React 官方已经不推荐大家在 componentWillMount 里做任何事情、到现在 React16 直接废弃了这个生命周期,足见其鸡肋程度了;
  4. render:这是所有生命周期中唯一一个你必须要实现的方法。一般来说需要返回一个 jsx 元素,这时 React 会根据 props 和 state 来把组件渲染到界面上;不过有时,你可能不想渲染任何东西,这种情况下让它返回 null 或者 false 即可;
  5. componentDidMount:会在组件挂载后(插入 DOM 树中后)立即调用,标志着组件挂载完成。一些操作如果依赖获取到 DOM 节点信息,我们就会放在这个阶段来做。此外,这还是 React 官方推荐的发起 ajax 请求的时机。该方法和 componentWillMount 一样,有且仅有一次调用。

React 废弃了哪些生命周期?为什么?

被废弃的三个函数都是在render之前,因为fber的出现,很可能因为高优先级任务的出现而打断现有任务导致它们会被执行多次。另外的一个原因则是,React想约束使用者,好的框架能够让人不得已写出容易维护和扩展的代码,这一点又是从何谈起,可以从新增加以及即将废弃的生命周期分析入手

1) componentWillMount

首先这个函数的功能完全可以使用componentDidMount和 constructor来代替,异步获取的数据的情况上面已经说明了,而如果抛去异步获取数据,其余的即是初始化而已,这些功能都可以在constructor中执行,除此之外,如果在 willMount 中订阅事件,但在服务端这并不会执行 willUnMount事件,也就是说服务端会导致内存泄漏所以componentWilIMount完全可以不使用,但使用者有时候难免因为各 种各样的情况在 componentWilMount中做一些操作,那么React为了约束开发者,干脆就抛掉了这个API

2) componentWillReceiveProps

在老版本的 React 中,如果组件自身的某个 state 跟其 props 密切相关的话,一直都没有一种很优雅的处理方式去更新 state,而是需要在 componentWilReceiveProps 中判断前后两个 props 是否相同,如果不同再将新的 props更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。类似的业务需求也有很多,如一个可以横向滑动的列表,当前高亮的 Tab 显然隶属于列表自身的时,根据传入的某个值,直接定位到某个 Tab。为了解决这些问题,React引入了第一个新的生命周期:getDerivedStateFromProps。它有以下的优点∶

  • getDSFP是静态方法,在这里不能使用this,也就是一个纯函数,开发者不能写出副作用的代码
  • 开发者只能通过prevState而不是prevProps来做对比,保证了state和props之间的简单关系以及不需要处理第一次渲染时prevProps为空的情况
  • 基于第一点,将状态变化(setState)和昂贵操作(tabChange)区分开,更加便于 render 和 commit 阶段操作或者说优化。

3) componentWillUpdate

与 componentWillReceiveProps 类似,许多开发者也会在 componentWillUpdate 中根据 props 的变化去触发一些回调 。 但不论是 componentWilReceiveProps 还 是 componentWilUpdate,都有可能在一次更新中被调用多次,也就是说写在这里的回调函数也有可能会被调用多次,这显然是不可取的。与 componentDidMount 类 似, componentDidUpdate 也不存在这样的问题,一次更新中 componentDidUpdate 只会被调用一次,所以将原先写在 componentWillUpdate 中 的 回 调 迁 移 至 componentDidUpdate 就可以解决这个问题。

另外一种情况则是需要获取DOM元素状态,但是由于在fber中,render可打断,可能在wilMount中获取到的元素状态很可能与实际需要的不同,这个通常可以使用第二个新增的生命函数的解决 getSnapshotBeforeUpdate(prevProps, prevState)

4) getSnapshotBeforeUpdate(prevProps, prevState)

返回的值作为componentDidUpdate的第三个参数。与willMount不同的是,getSnapshotBeforeUpdate会在最终确定的render执行之前执行,也就是能保证其获取到的元素状态与didUpdate中获取到的元素状态相同。官方参考代码:

代码语言:javascript
复制
class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 我们是否在 list 中添加新的 items ?
    // 捕获滚动位置以便我们稍后调整滚动位置。
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
    // 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
    //(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}
复制代码

react有什么优点

  • 提高应用性能
  • 可以方便的在客户端和服务端使用
  • 使用jsx模板进行数据渲染,可读性好

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • key改了,会发生什么,会执行哪些周期函数?
    • 组件通信的方式有哪些
      • state 和 props 触发更新的生命周期分别有什么区别?
        • React中可以在render访问refs吗?为什么?
          • 对 React-Intl 的理解,它的工作原理?
            • 对有状态组件和无状态组件的理解及使用场景
              • React组件的构造函数有什么作用?它是必须的吗?
                • 在React中组件的this.state和setState有什么区别?
                  • 当调用setState时,React render 是如何工作的?
                • 在React中如何避免不必要的render?
                  • React的生命周期有哪些?
                    • 1)组件挂载阶段
                    • 2)组件更新阶段
                    • 3)组件卸载阶段
                    • 4)错误处理阶段
                  • React 废弃了哪些生命周期?为什么?
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档