Skip to content

When returning null, <noscript /> tag is always rerendered #2770

@zpao

Description

@zpao

tl;dr: If you have a component that returns null and it rerenders, the noscript tag is unmounted and a new one is created because shouldUpdateReactComponent gets <ReactEmptyComponentType /> and null and returns false.


This came out of some internal components that were breaking after the most recent update.

I haven't gone to see if this is more widely broken - it might have been before any of the recent updates, just that the empty component is triggering it reliably. I've been some reports of <img> having similar weird problems that we couldn't track down. It's use of LocalEventTrapMixin is very similar to what's happening in ReactEmptyComponentType.

The trigger here is that we're triggering an update during the mount phase. When we do this <Child key="0"> works correctly because it's before <Child key="1"> which is triggering Parent to rerender. <Child key="2"> is the broken one because its componentDidMount hasn't been called yet. So we actually call its componentWillUnmount first. Then we still call its componentDidMount.

There's also the whole question of why we're trying to unmount anything at all here. It seems like we shouldn't be doing that.

cc @sebmarkbage @spicyj

Drop this into examples/basic-jsx-harmony and debug with pausing on caught exceptions. I added some breakpoints in ReactEmptyComponent to make it super obvious.

'use strict';

var Child = React.createClass({
  componentDidMount() {
    this.props.onMount && this.props.onMount();
  },
  render() {
    if (!this.props.visible) {
      return null;
    }

    return <div>hello world</div>;
  }
})


var Parent = React.createClass({
  update() {
    this.forceUpdate();
  },
  render() {
    return (
      <div>
        <Child key="0" visible={false} />
        <Child key="1" visible={true} onMount={this.update} />
        <Child key="2" visible={false} />
      </div>
    );
  }
})

React.render(
  <Parent/>,
  document.getElementById('container')
);

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions