react: findDOMNode() throws inside Suspense

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

I have a component which listens for resize events (via a BlueprintJS ResizeSensor). When loading a component dynamically with lazy / Suspense, an exception occurs as the resize sensor appears to be unmounted:

Uncaught Error: Unable to find node on an unmounted component.
    at invariant (29.chunk.js:86295)
    at findCurrentFiberUsingSlowPath (29.chunk.js:90628)
    at findCurrentHostFiber (29.chunk.js:90640)
    at findHostInstanceWithWarning (29.chunk.js:106349)
    at findDOMNode (29.chunk.js:106869)
    at ResizeSensor.componentDidUpdate (29.chunk.js:10535)

The resize sensor should be removing listeners on unmount.

Demo: https://codesandbox.io/s/n4241q075l Related: https://github.com/palantir/blueprint/issues/3141

What is the expected behavior?

No exception is thrown.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

Tested with:

  • React 16.6.1, fails
  • React 16.6.0, works

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 7
  • Comments: 19 (1 by maintainers)

Commits related to this issue

Most upvoted comments

@gaearon @acdlite, Seems it still happens. ~I tried to get mini reproduce but it seems happened in complex environment.~

User report reproduce: https://codesandbox.io/s/antd-reproduction-template-sbsiz Quick click the nav item will throw with Unable to find node on an unmounted component.

ref: https://github.com/ant-design/ant-design/issues/17016


Update:

Create a mini reproduce about this: #15857

Sorry, we didn’t release the fix yet.

@gaearon

any new updates?

@gaearon any ETA on when this will be available?

This will get into the next release then.

We’ve published 0.0.0-db3ae32b8 of all packages, which includes this fix. It is likely to be a release candidate for 16.9.0. You can give it a try now and see whether it resolves the issue for you. Thanks.

16.9.0 hadn’t fix this bug!

@MissLlq All reproductions linked in this issue (https://codesandbox.io/s/zwzqp18ool and https://codesandbox.io/s/n4241q075l) no longer crash with 16.9.

If you still encounter this error message with 16.9 please open a new issue.

We’ve published 0.0.0-db3ae32b8 of all packages, which includes this fix. It is likely to be a release candidate for 16.9.0. You can give it a try now and see whether it resolves the issue for you. Thanks.

We are blocked by this, too (without a pretty significant workaround). Any sense of a release timeframe? @gaearon? Is there some way to find out (in general) when the “next” release is? Sorry if this is covered somewhere…

For the record, this is surfacing for us through Semantic UI React Dropdown. So we’re beholden to them as well, but they point us here for the fix. 😃

Nope, it’s broken on master, and after bisecting, I confirmed the regression was caused by #14083

EDIT: Something else I found is that before the regression, ResizeSensor.componentDidUpdate doesn’t execute, but now it does.

EDIT 2: Yeah, ReactDOM.findDOMNode throws when invoked with a suspended component, here’s how you can reproduce.

const React = require("react");
const ReactDOM = require("react-dom");
const ReactTestRenderer = require("react-test-renderer");
const { Suspense } = React;

let didSuspend = false;
function Suspend() {
  if (!didSuspend)
    throw {
      then() {
        didSuspend = true;
      }
    };
  return null;
}

class Component extends React.Component {
  componentDidUpdate() {
    ReactDOM.findDOMNode(this);
  }

  render() {
    return null;
  }
}

function App() {
  return (
    <Suspense fallback="Loading">
      <Component />
      <Suspend />
    </Suspense>
  );
}

const root = ReactTestRenderer.create(<App />);
root.update(<App />);

This is true both before and after the aforementioned PR, so in any case it looks like it helped us discover this 😄

This sounds like a separate problem, can you provide a test case for it?

Welp, turns out I’m wrong, I actually made a mistake when mocking componentDidUpdate which resulted in it not being called 😝