【问题标题】:If I return jsx of a Component from some method and call that method in another component's render, then is a new object created on every render?如果我从某个方法返回组件的 jsx 并在另一个组件的渲染中调用该方法,那么每次渲染都会创建一个新对象吗?
【发布时间】:2020-08-26 08:40:12
【问题描述】:

如果我从某个方法返回一个组件的 jsx 并在另一个组件的渲染中调用该方法,那么每次渲染都会创建一个新对象吗?

class MyComponent extends React.Component {
  render = () =>(<h3>My Component</h3>)
}

function getEl(){ return (<MyComponent />) }

class Comp extends React.Component{
 componentDidMount = () =>{ 
   let ct = 100;
   const update = () => {
    if(ct-- < 0) return;
    this.setState({}, update);
   }
   update();
 } 
 render(){
  return (<div> {getEl()} </div>)
 }
}

如果 Comp 渲染 100 次,是否创建了 100 次 MyComponent 的新实例?如果传递给 MyComponent 的道具发生变化怎么办。然后? 寻找一些很好的深入解释为什么会发生这种情况

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

这些东西一开始可能会让人很困惑。甚至在你完成了最初的几项工作之后。 :-)

JSX &lt;MyComponent /&gt;React.createElement(MyComponent) 的简写。这样做是创建一个对象(“React 元素”),为 React 提供创建或更新组件实例所需的信息。它并不总是创建一个新的组件实例;如果该对象用于渲染某些内容的实例已经存在,则更新先前的实例。 JSX 本身的对象不是组件(实际上,您可以重用它们)。

为了完整性:即使组件被重新渲染,也不一定意味着它的所有 DOM 节点都被重新创建;它们可能会被更新,或者,如果是不必要的渲染,则完全不理会。​​p>

让我们扩展该代码以在 MyComponent 上包含一个 prop 并对其进行一些检测调用(在本例中为 console.logMutationObserver 进行花哨的谈话):

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        console.log(`MyComponent constructor, counter = ${this.props.counter}`);
    }
    render() {
        const { counter } = this.props;
        console.log(`MyComponent render, counter = ${counter}`);
        return <h3>My Component: {counter}</h3>;
    }
}

function getEl(counter) {
    console.log(`getEl, counter = ${counter}`);
    return <MyComponent counter={counter} />;
}

class Comp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0,
        };
    }
    componentDidMount() { 
        let counter = 0;
        const handle = setInterval(() => {
            ++counter;
            this.setState({counter});
            if (counter === 5) {
                clearInterval(handle);
            }
        }, 250);
    } 
    
    render() {
        const { counter } = this.state;
        console.log(`Comp render, counter = ${counter}`);
        return <div>{getEl(counter)}</div>;
    }
}

const root = document.getElementById("root");

const ob = new MutationObserver(records => {
    for (const record of records) {
        console.log(`DOM modification type: ${record.type} on ${record.target.nodeName}:`);
        if (record.type === "characterData") {
            console.log(`* Value: Changed from ${record.oldValue} to ${record.target.nodeValue}`);
        } else if (record.type === "attributes") {
            // We aren't listening for these
        } else {
            for (const node of record.removedNodes) {
                console.log(`* Removed: ${node.nodeName} with ${node.innerHTML || node.nodeValue || "(no value)"}`);
            }
            for (const node of record.addedNodes) {
                console.log(`* Added: ${node.nodeName} with ${node.innerHTML || node.nodeValue || "(no value)"}`);
            }
        }
    }
});
ob.observe(root, {
    childList: true,
    subtree: true,
    characterData: true,
    characterDataOldValue: true
});

ReactDOM.render(<Comp/>, root);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>

如您所见,MyComponent 构造函数仅被调用 一次 以创建 MyComponent 的单个实例,最初使用 counter = 0。之后,React 使用计数器值 1 到 5 更新了现有组件实例五次(我使用 5 而不是 100)。

由于MutationObserver,您还可以看到 DOM 修改:根组件获得了一个新的 H3,其中包含几个带有初始文本的文本节点,然后随着计数器的变化,只更新带有计数器的文本节点.

【讨论】:

    猜你喜欢
    • 2018-10-01
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    • 2019-04-19
    • 1970-01-01
    • 2021-12-04
    • 2021-08-17
    • 2021-01-09
    相关资源
    最近更新 更多