Search code examples
reactjsinnerhtmlreact-domreact-refouterhtml

React dom outerHTML seems not right?


I have created a demo.

demo url: https://4ikgc.csb.app/

Why the outerHTML always be <h1>abc</h1>

By the way, Why the console seems log everything twice.

Now the content of console.log are:

render h1: {current: null} undefined
render h1: {current: null} undefined
second abc <h1>abc</h1>
forth abc <h1>abc</h1>
first abc <h1>abc</h1>
first abc <h1>abc</h1>
third hello1 <h1>abc</h1>
third hello1 <h1>abc</h1>
fifth hello2 <h1>abc</h1>
fifth hello2 <h1>abc</h1>
render h1: <h1>​hello3​</h1>​ <h1>abc</h1>
render h1: <h1>​hello3​</h1>​ <h1>abc</h1>

But I thought the right content are:

render h1: {current: null} undefined
second abc <h1>abc</h1>
forth abc <h1>abc</h1>
first abc <h1>abc</h1>
third hello1 <h1>abc</h1>
fifth hello2 <h1>abc</h1>
render h1: <h1>​hello3​</h1>​ <h1>hello3</h1>

Hope anyone could help me! much thanks!

import React from "react";

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.h1 = React.createRef();
    this.state = {
      name: "abc"
    };
  }
  componentDidMount() {
    this.setState((state, props) => {
      console.log("first", state.name, this.h1.outerHTML);
      return {
        name: "hello1"
      };
    });
    console.log("second", this.state.name, this.h1.outerHTML);
    this.setState((state, props) => {
      console.log("third", state.name, this.h1.outerHTML);
      return {
        name: "hello2"
      };
    });
    console.log("forth", this.state.name, this.h1.outerHTML);
    this.setState((state, props) => {
      console.log("fifth", state.name, this.h1.outerHTML);
      return {
        name: "hello3"
      };
    });
  }
  render() {
    console.log("render h1:", this.h1, this.h1.outerHTML);

    return <h1 ref={ref => (this.h1 = ref)}>{this.state.name}</h1>;
  }
}

export default Hello;


Solution

  • Your Hello component have a H1 and where you're using that Hello component also have another H1

        <div className="App">
          <Hello />
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
        </div>
    
    

    Reason you're getting 2 console.logs is that how react lifecycle works. Your 1st console.log in render happens when the component initially get rendered. After component get rendered react triggers componentDidUpdate lifecycle method.

    Then when you trigger a this.setState in that method it triggers a re-render of render again. That's your second console.log. Also because in your particular case you're setting this.state multiple times in componentDidUpdate it triggers multiple state changes.

    Also make note that when in development mode and using react strict <React.StrictMode>, the setState get called twice. It is intentional. It won't happen in production.

    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      rootElement
    );
    

    REF:
    https://github.com/facebook/react/issues/12856#issuecomment-390206425

    https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects