question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

"passthrough" children don't re-render when parent changes

See original GitHub issue

Given the following Components with the following implementations:

home.js:

render () {
  return (
    <div className="home">
      <Router>
        <Route path='/'>
          <span>Hi from Index</span>
        </Route>
        <Route path='/user/martin'>
          <span>Hi Martin</span>
        </Route>
      </Router>
    </div>
  )
}

router.js:

componentDidMount () {
    var self = this;

    history.on('pushstate', function(pathname) {
      self.setState({});
    })

    history.on('popstate', function(pathname) {
      self.setState({})
    })
}

render () {
    return React.createElement('div', { className: 'Router' }, this.props.children);
}

route.js:

render () {
  if (!match(this.props.path)) return null;
  return React.createElement('div', { className: 'Route'}, children);
}

I’m running into the situation that since I’m not creating the <Route> in the parent and passing it through from the owner, the children do not re-render when the parent’s state changes.

What’s the best way around this? Seems like a pretty common use case.

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:12 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
sebmarkbagecommented, Jun 10, 2015

This is intentional. It is an optimization we’ve had for a long time and extremely rarely does it ever show up as an issue (as evident by the fact that @syranide didn’t even know about it).

Here is an example of one kind of optimization you can do (manually or automatically): https://github.com/facebook/react/issues/3226

It is also useful for container components that only updates their own state but their parents doesn’t rerender. E.g. a scrolling surface.

We do support mutation of your own state as a convenience but we do make certain assumptions about your code style.

This optimization relies heavily on the hard requirement that render must be pure, which is the only hard FP requirement of React:

  1. render should be idempotent. I.e. it should render the same thing regardless when it is called. Neither of these examples uses idempotent render functions since they’re reading from (globally) mutated state. (match and Date are not immutable) We’ve been thinking about ways of trying to enforce that. The ideal solution is to put time into your own state, but as a convenience you can call forceUpdate on something that you know is reading from global state whenever it changes. I.e. the thing calling match or getTime needs to call forceUpdate.

  2. render should not cause side-effects. Even if you use mutable state in your objects, you shouldn’t mutate them within the render.

ReactElements and their props are immutable. That is already enforced through Object.freeze and warnings. However, it is ok for state within them to be mutable. E.g. <Foo bar={this.state.mutableObject} />

We do have one heuristic. We assume that you won’t combine mutable state with reusable elements. E.g:

var mutableObject = { value: 1 };
var reusableElement = <Foo bar={mutableObject} />;

class App extends React.Component {
  componentDidMount() {
    mutableObject.value = 2;
    this.forceUpdate();
  }
  render() {
    return reusableElement;
  }
}

This last part is a heuristic assumption which has a theoretical case that doesn’t violate any of the other rules but still breaks. This case has never showed up yet AFAIK, because it is so awkward and unnatural way to structure your app in React.

However, the OP isn’t related to that, this is simply breaking rule number 1.

render should be idempotent.

0reactions
matthewmuellercommented, Jun 10, 2015

Awesome, yah I’m looking forward to that.

Appreciate all the help guys – keep up the great work.

Read more comments on GitHub >

github_iconTop Results From Across the Web

this.props.children not re-rendered on parent state change
As fas as I understand, if setState() is triggered, render function of Container component is called and all child elements should be re- ......
Read more >
The mystery of React Element, children, parents and re-renders
Looking into what is React Element, exploring various children vs parents relationship in React, and how they affect re-renders.
Read more >
How to use Props in React - Robin Wieruch
Since every state change in a component (here the parent component) causes a re-render of this and all child components, the child component ......
Read more >
Avoiding React component re-renders with React.memo
A component can re-render even if its props don't change. More often than not this is due to a parent component re-rendering causing...
Read more >
Using forwardRef in React to clean up the DOM
React forwardRef is a method that allows parent components pass down (i.e., “forward”) refs to their children. Using forwardRef in React gives ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found