reactjsreact-transition-groupreactcsstransitiongroup

CSSTransition nodeRef for component with direct children


I want to get rid of the warning on StrictMode for findDOMNode when using react-transition-group but I stumbled upon an issue.

My <Slide> component looks like this:

class Slide extends React.Component {
  nodeRef = React.createRef();

  render() {
    return (
      <CSSTransition
        in={this.props.in}
        timeout={ANIMATION_DURATION}
        mountOnEnter={true}
        unmountOnExit={true}
        classNames={{
          enter: "slideEnter",
          enterActive: "slideEnterActive",
          exit: "slideExit",
          exitActive: "slideExitActive"
        }}
        nodeRef={this.nodeRef}
      >
        {this.props.children}
      </CSSTransition>
    );
  }
}

It receives a Drawer element as children, the Drawer component looks like this:

class Drawer extends React.Component {
  render() {
    return (
      <div className="drawer">
        <button onClick={this.props.onClose}>close me</button>{" "}
        <div>This is my drawer</div>
      </div>
    );
  }
}

I cannot wrap the children element with a HTML tag (to attach a ref <div ref={this.nodeRef}>{this.props.children}</div> because it breaks the animation of the content. (I'm using this for children that are different drawers with position absolute)

I've also tried with cloneElement but it still doesn't work (with the code from below it behaves like this: 1. in no animation, 2. out no animation, 3. in animation works but I get the warning findDOMNode so it seems that nodeRef is sent as null, 4. out animation does not work.

const onlyChild = React.Children.only(this.props.children);
const childWithRef = React.cloneElement(onlyChild, {
  ref: this.nodeRef;
});

Is there any solution for this situation? Thanks!


Solution

  • The problem is that nodeRef needs to point to a DOM Node, as the name suggests, in your case it points to an instance of the Drawer class. You have two options:

    1. Pass the ref through another prop, e.g. forwardedRef, and in the Drawer class pass that prop to the root element:
    React.cloneElement(onlyChild, {
      forwardedRef: this.nodeRef,
    })
    
    <div ref={this.props.forwardedRef} className="drawer">
    
    1. Convert Drawer to a function component and use React.forwardRef:
    const Drawer = React.forwardRef((props, ref) => {
      return (
        <div ref={ref} className="drawer">
          <button onClick={props.onClose}>close me</button>{" "}
          <div>This is my drawer</div>
        </div>
      );
    });