当前位置: 首页 > 面试题库 >

防止反应将未更改的组件呈现到虚拟DOM中

姜烨伟
2023-03-14
问题内容

我已经在打字稿中使用React编写了一个简单的treeview来渲染DOM。

每个节点都必须遵循简单的界面。

interface INode {
    label: string;
    children: INode[];
}

然后通过以下方式描述该树:

var tree = {
    label: "root",
    children: [
        {
            label: "node 1",
            children: [
                {
                    label: "node 1.0",
                    children: []
                },
                {
                    label: "node 1.1",
                    children: []
                }
            ]
        },
        {
            label: "node 2",
            children: []
        }
    ]
};

很简单。组件现在也非常简单。对于节点,我有:

class Node extends React.Component<INode, void>{
    render() {
        console.log(`Rendering ${this.props.label}`);
        var list = this.props.children.map((node, i) => <li key={i}><Node {...node}/></li>);
        return (
            <div>
                <span>{this.props.label}</span>
                {this.props.children.length > 0 ? <ul>{list}</ul> : ""}
            </div>
        );
    }
}

对于树的根,我使用状态而不是道具。但是1秒钟后,我刷新了状态。但是状态本身不会改变:

class Root extends React.Component<void, INode>{
    constructor() {
        super();
        this.state = tree;
    }

    componentWillMount() {
        setTimeout(() => {
            this.setState((prevState: INode, props: void) => {
                console.log(`Updating state of ${this.state.label}`);
                return prevState;
            });
        }, 1000);
    }

    render() {
        var list = this.state.children.map((node, i) => <li key={i}><Node {...node} /></li>);
        return (
            <div>
                <span>{this.state.label}</span>
                {this.state.children.length > 0 ? <ul>{list}</ul> : ""}
            </div>
        );
    }
}

要运行此应用程序,只需执行以下几行代码

ReactDOM.render(
    <Root/>,
    document.getElementById("app")
);

呈现的html看起来应该正确。我现在的问题是当我查看浏览器控制台时

渲染节点1

渲染节点1.0

渲染节点1.1

渲染节点2

更新根的状态

渲染节点1

渲染节点1.0

渲染节点1.1

渲染节点2

整棵树被重新放置(进入虚拟DOM),而状态的值和子代的道具没有改变。

假设渲染过程将非常复杂且耗时。是否有可能停止将儿童重新提交到虚拟DOM中?


问题答案:

首先,除非您在应用程序中看到需要,否则不要花时间在此上。根据虚拟DOM进行检查是一项非常便宜的操作。但是,如果您需要优化应用程序,则可以通过一些策略来实现。

防止反应将未更改的组件呈现到虚拟DOM中(如您所要求的)

有两种广泛的方法可以这样做:

  • 不重新渲染将产生相同输出的组件
  • 除非更改,否则不对组件应用更改

不重新渲染将产生相同输出的组件

您可以避免使用shouldComponentUpdate进行重新渲染。为了shouldComponentUpdate提高效率,您可以使用框架来确保状态中只有不可变的对象,或者您可以简单地养成不变异对象,而是创建新对象的习惯。请参阅React不变性助手。在将nextState和nextProps与当前状态和props比较时,这将使您可以进行浅层检查(可以使用shallowCompare轻松完成)。

不对组件应用不变

这意味着仅当新值与当前值不同时才 更新 状态或道具。这种方法并不经常提出,但我认为它值得一提。

状态: 只有做到setState({ value: newValue }),如果newValue !== this.state.value。这可以通过多种方法来实现,但是一种方法是实际在进行检查之前进行检查setState()

道具: 如果非变化来自道具,则通常是因为父组件拥有一个值(处于其状态)作为道具传递给其 另一个
子级中的一个。然后,父组件需要重新渲染自己及其所有子组件。如果只希望更改依赖于值的组件,则可以让这些组件监听 全局应用程序状态
的一部分,并仅注入对该组件有用的内容。这样,该值将直接传递给对它感兴趣的那些组件,而不会重新渲染其他组件。

(在多个组件依赖同一数据的情况下,这消除了将状态存储在公共父组件中的需求。除了提高效率之外,这通常还使得创建依赖于现有组件某些部分的新组件更加容易。应用状态。)

您可以使用Flux,Redux或Baobab维护全局应用程序状态
,仅举几个例子。

使用 全局应用程序状态的
另一个优势是,您可以实现检查(在应用程序状态处理程序中),以确保仅通过实际更改来更新应用程序状态(即,如果设置的值与以前相同,则不设置值)。

组件更小:减少每次更改要重新呈现的DOM元素的数量

减少重新渲染成本的另一种策略是使组件更小。然后,每个数据更改仅适用于DOM的一小部分,因为每个组件具有较少的要呈现的元素。

我认为您应该 始终尝试这样做 ,因为除了性能方面,它还使您的代码更易于理解,可重用和可维护。

选择策略

每种策略都可以单独使用或结合使用,但是应用第一组中的两种策略通常不会显示出仅应用其中一种的显着改进。

我建议从缩小组件的角度开始,因为如上所述,这样做还具有其他优点。



 类似资料:
  • 在经历反应时,我产生了以下疑问: > DOM操作非常昂贵 但是最终react也会进行DOM操作。我们无法使用虚拟DOM生成视图。 折叠整个DOM并构建它会影响用户体验。 我从来没有这样做过,我主要做的是更改所需的子节点(而不是折叠整个父节点)或附加由JS生成的HTML代码。 例子: > 当用户向下滚动时,我们将帖子附加到父元素,甚至react也必须以同样的方式执行。没有人会因此而毁掉整个dom。

  • 我在一个表单上有一个TextField输入,问题是当我在它上键入时,刚刚键入的值的显示/呈现有一种延迟,我想防止这种延迟。 代码:

  • 我使用Rails与反应宝石和react-router.js内部资产。我使用webpack为了使用需要 我有我的路线内的应用程序。js: 另外es6。jsx: 当我访问controller_name/index时,默认情况下,它会呈现带有“#hello”链接的“欢迎组件”文本,但单击时,它不会执行任何操作。它仍然在说“欢迎组件” 我做错了什么?

  • 我从这里修改了以下组件定义,如下所示。但是,与示例不同的是,每次在组件上移动鼠标时,组件都会重新呈现。 重新渲染非常引人注目: 有人知道为什么会这样吗?

  • 前言 vdom 是 vue 和 React 的核心,先讲哪个都绕不开它。 vdom 比较独立,使用也比较简单。 如果面试问到 vue 和 React 和实现,免不了问 vdom: vdom 是什么?为何会存在 vdom? vdom 的如何应用,核心 API 是什么 介绍一下 diff 算法 什么是 vdom 什么是 vdom DOM操作是昂贵的。 步骤一:用JS对象模拟DOM树 步骤二:比较两棵虚

  • 我正在用chart.js.建立一个动态图表 在组件DDMount中,我使用setInterval每秒钟调用getNewData()。 这会更新我的数据集中的数据,由于某些原因,图表在状态更新时不会更新/重新呈现。 添加新数据时,如何让图表更新其点? 组件代码:

  • 但是当我从ComponentOne切换到ComponentTwo,然后回到ComponentOne时,它被重新构建,我失去了在ComponentOne中已经做过的一切 是否有一种方法,当创建的组件没有呈现时,它不会丢失其所有状态?

  • 我正在学习React钩子,这意味着我将不得不从类转移到函数组件。以前,在类中,我可以拥有与状态无关的类变量,我可以在不重新呈现组件的情况下更新这些变量。现在我试图用钩子重新创建一个组件作为函数组件,我遇到了这样一个问题:我不能(就我所知)为该函数创建变量,因此存储数据的唯一方法是通过钩子。然而,这意味着每当该状态更新时,我的组件将重新呈现。 我已经在下面的示例中说明了这一点,我试图将类组件重新创建