是否可以在不更改道具和状态的情况下重新渲染组件?

时间:2019-03-14 07:51:22

标签: reactjs

2 个答案:

答案 0 :(得分:1)

我尝试给出一个答案,并举例说明我在说什么。不过,您可能还需要等待其他人给出其他答案。

简短的故事:是的,子组件将被重新渲染,这是因为,作为要重新渲染的组件的子组件,其render()方法将被调用,原因是“瀑布效应”:render()方法中的每个Component都可以看作一个函数,因此,如果调用render()方法,则其内部的所有函数都会被再次调用,从而导致重新渲染。

但是,重要的是,即使子组件被重新渲染,这也不意味着DOM会改变!实际上,这不会发生,这是由于React对帐:https://reactjs.org/docs/reconciliation.html
基本上,React足够聪明,可以查看DOM中是否有更改,并替换实际需要更改的DOM元素(这确实很简单)。

现在,关于示例,请看这个小提琴:

class Child extends React.Component {
    /* Un-commeting this function, you can see that the render() method is not called agian.
    shouldComponentUpdate(nextProps, nextState) {
        if (JSON.stringify(nextProps) === JSON.stringify(this.props) &&
            JSON.stringify(nextState) === JSON.stringify(this.state)) {
            return false;
        }
        return true;
    }*/
    
    render() {
        console.log("Child's rendering");
        
        return (
            <p>Child says "Hello World"</p>
        );
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);
        
        this.state = {show: false};
    }
    
    render() {
        return (
            <div>
                <button onClick={() => this.setState({show: !this.state.show})}>Toggle</button>
                {this.state.show && <p>Parent says: Hello World!</p>}
                <Child />
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));
@import url(https://fonts.googleapis.com/css?family=Montserrat);

body {
    font-family: 'Montserrat', sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id='root'></div>

每次单击按钮时,控制台中都会显示一条消息Child's rendering,因此Child组件正在运行其render()方法。

但是!如果检查DOM,则在单击按钮时,屏幕上会显示消息“父母说:Hello World”,这就是DOM中发生的情况: enter image description here

如您所见,DOM中只有带有消息的<p>元素正在更改!!

相反,当再次单击该按钮并且消息消失时,会发生这种情况: enter image description here

在这种情况下,父<div>元素正在更改,并且仅在更改,这是因为我们已删除其子元素之一。

答案 1 :(得分:0)

这是必要的因为我们正在使用JavaScript,所以我们可以更改子代。我们可以向它们发送特殊属性,确定是否要渲染它们,并通常按照我们的意愿进行操纵。

如果不想每次更新React's PureComponent时都更新Child Component,则可以使用Parent Component

您可以使用shouldComponentUpdate来防止重新呈现子组件。它可以用于防止在细粒度的级别呈现组件: 您可以将相等性检查应用于不同的道具和状态,也可以将其用于其他类型的检查。但是,假设您不希望自己检查每个传入的道具,这也很容易出错,而只是在组件的任何相关内容(道具,状态)未发生变化时才防止重新渲染。在这里,您可以使用更广泛但更简单的解决方案来防止重新呈现:React’s PureComponent

import React, { Component, PureComponent } from 'react';

...

class Square extends PureComponent {
  render() {
    return <Item>{this.props.number * this.props.number}</Item>;
  }
}

React的PureComponent对组件的道具和状态进行了浅浅的比较。如果什么都没有改变,它将阻止组件的重新呈现。如果发生更改,它将重新提供组件。