首页 > 解决方案 > 准系统 React 应用程序实例化应用程序并调用两次渲染

问题描述

使用npx create-react-app reactTwice,我创建了一个准系统 React 应用程序,除了在控制台中记录某些操作之外什么都不做。这表明主 App 类被实例化了两次,并且它的render方法被调用了两次,即使this.stateand的值this.props没有改变。

我想了解为什么会这样。也许有一种方法可以避免它,也许发生这种情况有一个我需要考虑的具体原因。

您可以在此处找到此存储库。(请注意,在类似 jsFiddle 的站点上运行类似代码时不会发生此行为)。

这是启动应用程序的 index.js 脚本:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

console.log("ReactDOM.render() about to be called")

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

console.log("ReactDOM.render() was called")

这是生成App类的脚本:

import React from 'react';

let instance = 0

export default class App extends React.Component {
  constructor(props) {
    super(props)
    this.startTime = + new Date()
    this.instance = ++instance
    this.state = {}
    this.imageError = this.imageError.bind(this)

    console.log("App constructor (", this.instance, ")", this.getTime())
  }


  getTime() {
    return + new Date() - this.startTime 
  }


  runTimeOutMethod() {
    console.log("runTimeOutMethod started (", this.instance, ")", this.getTime())
    this.setState({ time: true })
    console.log("runTimeOutMethod complete (", this.instance, ")",  this.getTime())
  }


  imageError(event) {
    console.log("DOM element added (", this.instance, ")", this.getTime())
  }


  render() {
    console.log(
      "render called (", this.instance, ")"
    ,  this.getTime()
    , this.state
    , this.props
    )

    return (
      <div className="App">
       <img src="" alt="no src" onError={this.imageError} />
      </div>
    );
  }


  componentDidMount() {
    console.log("componentDidMount started (", this.instance, ")", this.getTime())
    this.setState({ mounted: true })
    setTimeout(this.runTimeOutMethod.bind(this), 0)
    console.log("componentDidMount complete (", this.instance, ")", this.getTime())
  }
}

这是控制台中的示例输出。为了便于阅读,我添加了格式。

index.js: 5 ReactDOM.render() about to be called

App.js:14 App constructor ( 1 ) 0
App.js:14 App constructor ( 2 ) 0

App.js:36 render called ( 2 ) 1 {} {}
App.js:36 render called ( 2 ) 2 {} {}

App.js:52 componentDidMount started ( 2 ) 24
App.js:55 componentDidMount complete ( 2 ) 26
App.js:36 render called ( 2 ) 29 {mounted: true} {}
App.js:36 render called ( 2 ) 29 {mounted: true} {}

index.js:14 ReactDOM.render() was called

App.js:31 DOM element added ( 2 ) 46

App.js:24 runTimeOutMethod started ( 2 ) 47
App.js:36 render called ( 2 ) 48 {mounted: true, time: true} {}
App.js:36 render called ( 2 ) 48 {mounted: true, time: true} {}
App.js:26 runTimeOutMethod complete ( 2 ) 49

标签: reactjs

解决方案


此问题的所有症状都是由文件中的使用引起的<React.StrictMode>index.js这是预期的行为。丹·阿布拉莫夫写道:

StrictMode 的全部目的是找出应该是纯的用户编写的函数实际上不是纯的...... [这不是错误,而是突变或副作用。是的,[调用两次] 是任意的,但我们发现它在实践中非常有效。

如果您将其更改为以下内容,则这些副作用将停止发生index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';


ReactDOM.render(
  <>
    <App />
  </>,
  document.getElementById('root')
);

在任何情况下,对构造函数和 to 的双重调用render都不会在生产模式下进行。


推荐阅读