Home > Back-end >  componentDidUpdate is not fired
componentDidUpdate is not fired

Time:01-11

In my source code, the height of the component EditorBasic that I measure by .current.clientHeight changes when resizing the window, which is not correct. To reproduce the bug, I wrote the following smaller code.

I used aRef to refer to EditorBasic and expected to get its height. I expect the following code to have the following behaviour:

  1. When we click on "Click to toggle EditorBasic", by updateTrigger, EditorBasic will trigger handleResize.

  2. handleResize calls calculateNextHeight which can print the height of the EditorBasic so that I could check.

But I cannot pass the 1st step; changing updateTrigger cannot trigger handleResize; the log componentDidUpdate is not printed.

Does anyone know why?

StackBlitz: https://stackblitz.com/edit/react-ts-j4pm8x?file=App.tsx,EditorBasic.tsx

import * as React from 'react';
import EditorBasic from './EditorBasic';

interface IAppProps {}

interface IAppState {
  showEditorBasic: boolean;
  updateTrigger: number;
}

export default class App extends React.Component<IAppProps, IAppState> {
  aRef: any;

  constructor(props) {
    super(props);
    this.state = {
      showEditorBasic: false,
      updateTrigger: 0,
    };
    this.aRef = React.createRef();
  }

  calculateNextHeight = () => {
    console.log(
      'this.aRef.current.clientHeight',
      this.aRef.current.clientHeight
    );
  };

  render() {
    return (
      <div>
        <div
          onClick={() =>
            this.setState({
              showEditorBasic: !this.state.showEditorBasic,
              updateTrigger: this.state.updateTrigger   1,
            })
          }
        >
          Click to toggle EditorBasic
        </div>
        {this.state.showEditorBasic && (
          <div ref={this.aRef}>
            <EditorBasic
              calculateNextHeight={this.calculateNextHeight}
              updateTrigger={this.state.updateTrigger}
            />
          </div>
        )}
      </div>
    );
  }
}
import * as React from 'react';

interface IEditorBasicProps {
  calculateNextHeight: any;
  updateTrigger;
}

interface IEditorBasicState {}

export default class EditorBasic extends React.Component<
  IEditorBasicProps,
  IEditorBasicState
> {
  handleResize() {
    // console.log('handleResize');
    this.props.calculateNextHeight();
  }

  componentDidMount() {
    // console.log('componentDidMount');
    window.addEventListener('resize', this.handleResize.bind(this));
  }

  componentDidUpdate(prevProps) {
    console.log('componentDidUpdate');
    if (this.props['updateTrigger'] !== prevProps['updateTrigger']) {
      this.handleResize();
    }
  }

  render() {
    return (
      <div>
        <br />
        <br />
        EditorBasic {this.props.updateTrigger}
        <br />
        <br />
      </div>
    );
  }
}

CodePudding user response:

React documents for componentDidUpdate:

Called immediately after updating occurs. Not called for the initial render.

And you are rendering the EditorBasic when showEditorBasic is present and changing its props is simultaneous with the initial rendering.

CodePudding user response:

The property showEditorBasic is completely recreateing the BasicEditor. In that case, the component will only trigger the componentDidMount function.

Try to call handleResize inside componentDidMount and render the aRef div outside your if statement.

App

import * as React from 'react';
import EditorBasic from './EditorBasic';

interface IAppProps {}

interface IAppState {
  showEditorBasic: boolean;
  updateTrigger: number;
}

export default class App extends React.Component<IAppProps, IAppState> {
  aRef: any;

  constructor(props) {
    super(props);
    this.state = {
      showEditorBasic: false,
      updateTrigger: 0,
    };
    this.aRef = React.createRef();
  }

  calculateNextHeight = () => {
    console.log(
      'this.aRef.current.clientHeight',
      this.aRef.current.clientHeight
    );
  };

  render() {
    return (
      <div>
        <div
          onClick={() =>
            this.setState({
              showEditorBasic: !this.state.showEditorBasic,
              updateTrigger: this.state.updateTrigger   1,
            })
          }
        >
          Click to toggle EditorBasic
        </div>
          <div ref={this.aRef}>
            {this.state.showEditorBasic && (
              <EditorBasic
                calculateNextHeight={this.calculateNextHeight}
                updateTrigger={this.state.updateTrigger}
              />
            )}
        </div>
      </div>
    );
  }
}

EditorBasic

import * as React from 'react';

interface IEditorBasicProps {
  calculateNextHeight: any;
  updateTrigger;
}

interface IEditorBasicState {}

export default class EditorBasic extends React.Component<
  IEditorBasicProps,
  IEditorBasicState
> {
  handleResize() {
    // console.log('handleResize');
    this.props.calculateNextHeight();
  }

  componentDidMount() {
    // console.log('componentDidMount');
    window.addEventListener('resize', this.handleResize.bind(this));
    this.handleResize();
  }

  componentDidUpdate(prevProps) {
    console.log('componentDidUpdate');
    if (this.props['updateTrigger'] !== prevProps['updateTrigger']) {
      this.handleResize();
    }
  }

  render() {
    return (
      <div>
        <br />
        <br />
        EditorBasic {this.props.updateTrigger}
        <br />
        <br />
      </div>
    );
  }
}
  • Related