【问题标题】:React: Calling Render() during animation. What happens?React:在动画期间调用 Render()。发生什么了?
【发布时间】:2021-04-23 01:20:06
【问题描述】:

我想知道 React 如何处理在组件动画期间调用的 Render。在下面的示例中,重新渲染了一个组件

假设在组件动画期间组件的状态发生了变化,因此组件被重新渲染。 react 会取代物理 DOM 还是会识别出组件处于动画中间? 这是我认为会发生的事情

第 1 步:组件安装 组件首次挂载到物理 DOM。组件的动画持续 60 秒。该组件有一个更改状态计时器,该计时器将在 30 秒内关闭。同时,react 会在挂载时保存虚拟 DOM。

第 2 步:触发状态更改并重新渲染组件 30 秒后,父组件会发生状态变化,组件将重新渲染。此时组件处于动画中间,并且使用 react-transition-group 将“className-active”css 类应用于子级。 React 现在会将当前的虚拟 DOM 与旧的虚拟 DOM 进行比较。虚拟 DOM 是不同的,因为孩子现在应用了活动类(而不是“进入”类)。因此,react 会将更新后的组件插入到物理 DOM 中(即使物理 DOM 不需要更新!)。因此,屏幕会闪烁...

这是描述上述场景的代码

import React from 'react'
import CSSTransition from 'react-transition-group'
                                                                                                                                                                                                                     ```
class ExampleComponent extends React.Component {
      constructor(props) {
           super(props);
           this.state = {reRender : false};
           setTimeout(() => {this.setState({reRender: true})}, 30000) 
           /* 30,000 ms is 30 seconds. 
              Set state will fire in 30 seconds, and the parent component will 
             rerender itself and the     
           */
     }
      render()  {
          return (
                <CSSTransition
            appear = {true}
            in = {true}
            classNames = 'test'
            timeout = {60000}>
                <span> test </span>
        </CSSTransition>
          )

      }

}

这里是相关的css类

.test-appear, test-enter{
       opacity : 1;
}
.test-appear-active, .test-enter-active {
      opacity: 0; 
      transition: opacity; 
      transition-duration: 60000;
}
.test-appear-done, .test-enter-done {
      opacity: 0;    
}

鉴于这段代码,我想逐步了解在反应生命周期和虚拟 DOM 中发生了什么。物理 DOM 会在 30 秒后更新还是会反应识别它处于动画中间?虚拟 DOM 是如何保存之前的状态的?

【问题讨论】:

    标签: javascript html css reactjs react-transition-group


    【解决方案1】:

    在这种情况下,CSSTransition 保持内部状态以了解它处于动画的哪个阶段。

    React 不会重置 CSSTransition 实例的状态,因为它知道它引用的是同一个元素(React 依赖于组件的类型和在树上的位置来决定它是同一个元素,还是 @ 987654325@ prop 定义)

    因为CSSTransition 的内部状态是相同的,所以它的 render 方法在组件状态更改前后呈现相同的 css 类。

    看看你的例子它没有闪烁https://codesandbox.io/s/hopeful-shaw-c9ldr

    CSSTransition 可能会更改状态以响应您传递给它的任何道具的变化(在这种情况下甚至不会发生)但这取决于CSSTransition 实现。

    最后,如果你将不同的key 传递给CSSTransition,它会重置动画,因为 React 会认为它是一个新组件,因此会卸载前一个组件并安装一个具有新内部状态的新组件。

    请参阅此处的动画重置示例: https://codesandbox.io/s/jolly-maxwell-2ihkf

    【讨论】:

      【解决方案2】:

      React 不关心动画。它所关心的只是确保 DOM 根据 vDOM 的变化进行更新。

      当您从 DOM 中间动画中手动移除元素时,动画将停止。 React 会做同样的事情,即对树的任何更改(不包括不改变树结构的 prop 更改)都将在下一个渲染周期立即卸载并重新安装涉及的元素。

      在你的情况下,由于树没有改变,它不会拆除任何元素。 render() 将被调用,react 将比较 vDOM 的新旧版本,如果有任何更改,将只修改 props。但是您手动重新渲染状态更改不会以任何方式影响 vDOM

      有关详细信息,请参阅 Reconciliation 文档。

      【讨论】:

      • 为什么 vdom 在我第二次调用 Render() 时没有改变?在第一次渲染 vdom 时,有一个 应用了 css enter 类。在第二次调用 render() 时,dom 应用了进入类。我认为的关键问题是:vdom 是否发生了变化?它知道dom已经改变了吗?如果不是,则 vdom 和 dom 不同步,但由于 vdom 在第二次调用 render() 时保持不变,因此在第二次调用 render() 时不会向 dom 插入任何新内容
      • 即使 vDOM 发生变化,也可能只是 prop 变化(在您的情况下为 className),它不会拆除现有的 dom 元素,只需修改它们即可。
      • 也许我说得不够清楚,实际的动画发生在 css 领域,动画时 dom 或 vDOM 没有任何变化
      • 我认为 DOM 发生了变化。当我检查元素并触发动画时,我看到进入类被应用于 DOM。我想知道 vdom 是否知道这一点。
      • 是的,这是 className 的更改,由 css 转换控制,但您在 30 秒后重新渲染的调用仍然无效
      猜你喜欢
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 2017-09-26
      • 2021-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多