Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: componentDidMountCalled before ref is set #28666

Open
CodeMedic42 opened this issue Mar 28, 2024 · 3 comments
Open

Bug: componentDidMountCalled before ref is set #28666

CodeMedic42 opened this issue Mar 28, 2024 · 3 comments
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug

Comments

@CodeMedic42
Copy link

I have encountered an issue where a class componentDidMount method is called before a ref is set in another. Also I am seeing sometimes it is being called twice, but not always. The ref is set in a class called Ex1 and the componentDidMount in a class called Ex2. There is also a forwardRef function component in the mix.

React version: 18.2.0

Steps To Reproduce

  1. Run "npx create-react-app my-app"
  2. Copy the code I have provided into app.js
  3. Run 'npm start'
  4. Open the dev tools and reload the page and follow the debugger points.

Here is a fiddle with the issue. Please note that I was having issues with jsFiffle.net not fully loading. I don't think it was my fiddle, but it was acting weird. If that happens just create your own fiddle from scratch and it should work.
https://jsfiddle.net/CodeMedic42/d50mnjz8/4/

Here is a copy of my code

import React, { useRef, Component, forwardRef } from 'react';

class Ex1 extends Component {
	render() {
		const {
			innerRef,
			children,
		} = this.props;

		return (
			<div
				ref={(element) => {
					console.log('This line is called after the componentDidMount in Ex2.');
					innerRef.current = element;
					debugger;
				}}
				className="ex1"
			>
				{children}
			</div>
		);
	}
}

class Ex2 extends Component {
	componentDidMount() {
		const { targetRef } = this.props;

		console.log('This line is hit before targetRef is set.');
        console.log('Also it appears to be called twice. Once before the ref is set and once after.');

		debugger;
	}
	
	render() {
		const {
			innerRef,
		} = this.props;

		return <div className="ex2">I do my own thing</div>;
	}
}

const Bar1 = forwardRef((props, ref) => {
	const {
		children,
	} = props;

	return (
		<Ex1 innerRef={ref}>
			{children}
		</Ex1>
	);
});

function Test() {
	const targetRef = useRef();

	return (
		<Bar1 ref={targetRef}>
			<Ex2 targetRef={targetRef}/>
		</Bar1>
	);
}

export default Test;

The current behavior

The componentDidMount method in Ex2 is called before, and sometimes after, the call to the ref function in Ex1.

The expected behavior

The componentDidMount method in Ex2 should be called once and after the ref is set in Ex1.

@CodeMedic42 CodeMedic42 added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Mar 28, 2024
@erikasby
Copy link

erikasby commented Mar 31, 2024

Added a couple of more debuggers.

Result:
Test > Bar1 > Ex1.render() > Ex2.render() > Ex2.componentDidMount() > Ex1 > Ex2.componentDidMount()

Further investigation is needed and maybe someone can explain if this is intentional behavior.

Click for code w/ added debuggers
import React, { useRef, Component, forwardRef } from "react";

class Ex1 extends Component {
  render() {
    const { innerRef, children } = this.props;

    debugger;
    return (
      <div
        ref={(element) => {
          console.log(
            "This line is called after the componentDidMount in Ex2."
          );
          innerRef.current = element;
          debugger;
        }}
        className="ex1"
      >
        {children}
      </div>
    );
  }
}

class Ex2 extends Component {
  componentDidMount() {
    const { targetRef } = this.props;

    console.log("This line is hit before targetRef is set.");
    console.log(
      "Also it appears to be called twice. Once before the ref is set and once after."
    );

    debugger;
  }

  render() {
    const { innerRef } = this.props;

    debugger;
    return <div className="ex2">I do my own thing</div>;
  }
}

const Bar1 = forwardRef((props, ref) => {
  const { children } = props;

  debugger;
  return <Ex1 innerRef={ref}>{children}</Ex1>;
});

function Test() {
  const targetRef = useRef();

  debugger;
  return (
    <Bar1 ref={targetRef}>
      <Ex2 targetRef={targetRef} />
    </Bar1>
  );
}

export default Test;

@Rishab49
Copy link

  1. I think this is the expected behavior as react renders children before the parent element, hence componentDidMount of Ex2 is called before the ref can be set on the parent i.e; div of Ex1
  2. componentDidMount is called twice because your app must be running in strict mode.

@erikasby
Copy link

  1. I think this is the expected behavior as react renders children before the parent element, hence componentDidMount of Ex2 is called before the ref can be set on the parent i.e; div of Ex1
  2. componentDidMount is called twice because your app must be running in strict mode.

I have somewhat similar conclusion to this. I guess this issue could be closed then @CodeMedic42?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug
Projects
None yet
Development

No branches or pull requests

3 participants