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

TypeError: Cannot read property '_currentElement' of null #4026

Closed
korakon opened this issue Jun 4, 2015 · 32 comments
Closed

TypeError: Cannot read property '_currentElement' of null #4026

korakon opened this issue Jun 4, 2015 · 32 comments

Comments

@korakon
Copy link

korakon commented Jun 4, 2015

From maintainers: if you have this problem, please see the explanation in #6895 (comment).

Test case: jsFiddle

The error is in this function, internalInstance is null.

  /**
   * Releases any resources allocated by `mountComponent`.
   *
   * @final
   * @internal
   */

  unmountComponent: function(internalInstance) {
    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
    internalInstance.unmountComponent();
  }

I managed to "fix" the bug by simply checking if internal state is not null but that requires modifying react.
Other mentions of this bug are listed below.

@syranide
Copy link
Contributor

syranide commented Jun 4, 2015

Some invariant violations leaves React in an unstable state at the moment so this is to be expected. AFAIK this is partly because catching and re-throwing errors is a crapshoot in many browsers and may also have significant performance impact on hot code-paths.

@korakon
Copy link
Author

korakon commented Jun 4, 2015

Some invariant violations leaves React in an unstable state at the moment so this is to be expected ...
AFAIK this is partly because catching and re-throwing errors is a crapshoot in many browsers

I am rethrowing the errors in the test case because it is easier to demonstrate that way, in an application I am developing, the error happens even when I am not re-throwing any errors, Here is an example.

The function I am using is something like this, it simply switches pages,
go(UserPage({user: {name: 'k'}) or shows an error page if an error happened.

function go(page) {
    try {
         React.render(App(null, page), mount);
    catch (e) {
         React.render(App(null, ErrorPage({error: e})), mount);
    }
}

Test case

Is there any way to manually clear the state besides removing and reinserting the dom element?
I tried React.unmountComponentAtNode() but it throws the same error.

@JohnyDays
Copy link

Perhaps have a higher level component AppWrapper, that contains that state? or pass page/ErrorPage as props, and do setProps on App (your top-level component)

@syranide
Copy link
Contributor

syranide commented Jun 4, 2015

@korakon It doesn't matter if you rethrow errors, my intended point was that React can internally catch and rethrow errors to avoid the internal state breaking (completely at least) but doesn't because there are undesirable side-effects in many browsers currently.

AFAIK there is no clean way out of an invariation violation once it has happened. If you have a particularily vulnerable piece of code then wrap that in a try-catch, not the calls to React.

@korakon
Copy link
Author

korakon commented Jun 4, 2015

@JohnyDays
Thank you, I will be using this.

@syranide
Yeah, I get your point know, Thank you.

@korakon korakon closed this as completed Jun 4, 2015
@blairanderson
Copy link

I am seeing this quite a bit, but very little headway towards finding the root cause.

on my local environment i can reproduce by adding an undefined variable into a function that changes the state of a component.

it throws as undefined, then all other attempts to render on the parent node fail with TypeError: Cannot read property '_currentElement' of null...

Is there a cool way to track stuff like this, given a giant component with a massive combinations of child components and states?

@JohnyDays
Copy link

This usually happens if you interrupt react's rendering cycle with an exception, you should take care not to do so, and you can usually catch them easily during dev. I have never had this happen in prod, so perhaps it's related to some dev-only cycle

@blairanderson
Copy link

@JohnyDays that makes sense.

Is there a way to force an unmount? I can't find any part of the api to do this.

Current solution is a try/catch around render(which sometimes throws while unmounting) then in catch replacing the element with a new one and rendering on the new element.

I'd like to have componentWillUnmount run for the components being unmounted(with force) and all its children before i remove the reference.

Can you think of any way to do this?

@jordancardwell
Copy link

@blairanderson FWIW, I recently found some sneaky regressions after migrating an app from 0.13 to 0.14.

After a lot of headache, I realized someone was mutating child props like

this.props.children[0].props.className = 'hidden'

This was hard to pinpoint, since the error didn't really point in any particular direction.

It was, however, easily fixed, once I found it by replacing with

var childrenWithNewProps = React.Children.map(this.props.children, function(child) {
  return React.cloneElement(child, { className: 'hidden' });
});

hopefully someone will find this helpful moving forward

@jimfb
Copy link
Contributor

jimfb commented Nov 4, 2015

@jordancardwell You should have gotten a warning for that in dev mode with React 0.13. We try to warn in the previous version whenever making breaking changes, such that if you fix all your warnings then the migration to the next version will go smoothly.

@jordancardwell
Copy link

@jimfb yeah, that's is actually something react is really good at, and has made migrating to new versions pretty pleasant for the most part.

I definitely missed a deep dark corner of the app when clearing up warnings before this update.

That said, for cases when this happens, a more specific/descriptive error could be really helpful.

Maybe (optionally) logging a dump describing the unexpected variation, when in dev mode(?).. anything to prevent a dev from iterating through rounds of commenting out components and chunks of render methods to pinpoint where the 'bad thing' happened, and what flavor of 'bad thing' it was. (in my case, directly mutating child props)

Being familiar with React internals, you probably have a better idea of how feasible this is.

@jimfb
Copy link
Contributor

jimfb commented Nov 9, 2015

@jordancardwell We did exactly that in 0.13.

Example text of error message:

Warning: Don't set .props.myFooProp of the React component <FooComponent />. Instead, specify the correct value when initially creating the element or use React.cloneElement to make a new element with updated props.

@jordancardwell
Copy link

@jimfb Right, I'm familiar with the warning messages about deprecations and breaking changes in future versions in React, and as I stated in the previous comment:

I definitely missed a deep dark corner of the app when clearing up warnings before this update.

I missed this particular warning in one area of our app before updating, but had corrected for the rest of the warnings that were thrown.

I was referring to the error message when something in your app causes an invariant violation in the current version (whatever it may be at the time). Some contextual information to point you in the right direction would be pretty valuable for anyone finding themselves in my situation.

React has always been extremely helpful with error messages and documentation around common errors. My comment about the feasibility of providing more information around invariant violations is to help in the situation where you've unwittingly done something stupid to cause it or failed to update something before a migration.

@jordancardwell
Copy link

So I supposed your point was that it's clearly feasible to do.. would it make sense to leave those descriptive messages in when people shoot foot-guns in dev mode.

So though it can still be a breaking change, the dev can get some helpful info.. you did this and it blew things up, we stopped allowing this in 0.13. get with the program.

@jimfb
Copy link
Contributor

jimfb commented Nov 9, 2015

@jordancardwell Don't we freeze the props in dev now? In most browsers, you should get an error (with stack trace) like:

Uncaught TypeError: Cannot assign to read only property 'foo' of #<Object>
Uncaught TypeError: Can't add property noise, object is not extensible

@tcurdt
Copy link

tcurdt commented Jan 6, 2016

Cannot read property '_currentElement' of null is such a useless error message. Is there a way to turn this into a more useful message that actually points to the problem?

@blairanderson
Copy link

It's because some child component or helper function prevented a render from completing, you can probably force render at the top and get the actual error to show up.

@tcurdt
Copy link

tcurdt commented Jan 9, 2016

Tracking down these errors is so killing productivity. I don't even know which component is causing this.
@blairanderson How do I get a proper error message? What do you mean by "force render at the top"?
Is there anything I could wrap in a try/catch to get to the cause of the error?

@Danita
Copy link

Danita commented Mar 3, 2016

I have a project set up with Webpack hot module reload. I can trigger this error (Uncaught TypeError: Cannot read property '_currentElement' of null in ReactReconciler.js) if I have some invalid code in a component, which triggers a expected exception, then correcting the invalid code, which causes the hot module reload, which seems to trigger this TypeError.

Summing up, in my case it's occurring on every hot module reload which results from correcting a javascript error.

@rossPatton
Copy link

i agree with @tcurdt on these vague errors killing productivity. i know this issue is closed and piling on prolly doesn't help much, but i've had massive problems trying to update the website at my work from react 12 (i know) to react 13, which in theory shouldn't be hard to do. but this one error is causing me a lot of grief, because it's not clear why it's happening, where it's happening, what's causing it, etc

@blairanderson
Copy link

@rossPatton in chrome you can activate pause on exception and track down which component path is breaking.

Almost always from rendering code throwing an error and preventing the render from completing.

@jameswomack
Copy link

@Danita Same here. Have you discovered a way to circumvent this error by forcing a refresh of the Webpack bundle?

@gaearon
Copy link
Collaborator

gaearon commented Apr 10, 2016

This error message usually just mean that render() of some component threw during the initial mount. If you look above this error message and ignore it, you will see the real error message.

@jameswomack
Copy link

My problem was that I had two React transforms, and the transform before
catch-errors was preventing catch-errors from working. Once I incorporated
error catching into the first transform, I was able to see the exact error
and HMR continued effectively.

On Sunday, April 10, 2016, Dan Abramov notifications@github.com wrote:

This error message usually just mean that render() of some component
threw during the initial mount. If you look above this error message
and ignore it, you will see the real error message.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#4026 (comment)

James J. Womack
Senior Software Engineer/Architect
Netflix

@asadighi
Copy link

React team can learn a thing or two from Angular team about handling/messaging these kind of errors

@art-in
Copy link

art-in commented Jun 20, 2016

@gaearon

This error message usually just mean that render() of some component threw during the initial mount.

Ok. But sad thing is that if you try to replace component that throws error in render() with another component (like, error message component) - "_currentElement" error will be frown again anyway.

My case:
I have global error handler set through window.onerror.
On window.onerror I'm setting ErrorScreen as current (which does not throw error in render()).

Now, my BadComponent throws error in render().
It is caught in window.onerror, ErrorScreen set. But react still re-throws "_currentElement"-error.
What I got is infinite error loop.

Why "_currentElement"-error is thrown if I'm not trying to render BadComponent any more?

@gaearon
Copy link
Collaborator

gaearon commented Jun 20, 2016

@artin-phares

React currently cannot recover from an error inside render. Even a custom onerror handler won’t help here—the library’s internal state becomes corrupted because of the error, and it can’t render “something else”. Until error boundaries are fully supported (you can track #2461), I think your best is to remove the container DOM element and create a new one where you’d render <ErrorScreen>. Not sure whether this would work, but there’s higher chance it will than if you just ReactDOM.render() into an existing container that’s messed up.

@art-in
Copy link

art-in commented Jun 20, 2016

@gaearon Ok. Looks like highly known issue. Thanks.

@blairanderson
Copy link

@oklas
Copy link

oklas commented Feb 21, 2017

What is exactly solved is meant by that:

this is being solved in v15 with unstable_handleError()

I have react 5.14.1 I only add to render() method the next:

(undefined).x

and see

Uncaught TypeError: Cannot read property '_currentElement' of null

@gaearon
Copy link
Collaborator

gaearon commented Feb 21, 2017

I posted an explanation about this problem here: #6895 (comment).
I am locking this thread for the same reasons I locked #6895.

I hope the explanation helps!

@facebook facebook locked and limited conversation to collaborators Feb 21, 2017
@gaearon
Copy link
Collaborator

gaearon commented Jul 27, 2017

A small update on this. We just released React 16 beta which shouldn’t emit cryptic errors like this one. Even if the application code swallows an error, React 16 will still print it to the console. It might be too early for you to try React 16 (since ecosystem is still preparing for it), but this error should never occur in the future after you switch to it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests