-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
props.activeRoute not re-rendered #34
Comments
Rendering the same component to the same element in React is essentially a no-op if nothing else has changed. To trigger another |
React should still call the render function of the Index component first. Only after that it should compare the output and decide if the real DOM needs to be updated. Consider the following setup. It is basically the same example with a static Index route and behaves as I expected. I'm managing data outside of React and just pass getter functions as props to components. I therefor need a way to force a re-render when data changes. var React = require('react')
var RRouter = require('react-nested-router')
var Router = RRouter.Router
var Route = RRouter.Route
var App = React.createClass({
render: function() {
console.log('render app')
return (
<div>
<h1>App</h1>
<Index />
</div>
)
}
})
var Index = React.createClass({
render: function() {
console.log('render index')
return <span>{Date.now()}</span>
}
})
var router = Router(<Route handler={App} />)
setInterval(function() {
router.renderComponent(document.body)
}, 1000) |
Why would it call the render method of |
Because React can't know if props changed. That's why it calls the render function of all nodes, even when they neither receive props nor have state. Look at this example. |
looks like react does in fact rerender even if the state hasn't changed: |
@hendrikcech Thanks for the example. I'm reopening this issue, tho I'm not sure how to address it. Our implementation of |
I'm not sure yet either. I looked into the commit history and now know that it used to work correctly up until d83cf7b. After that different bugs come up. Some builds throw this error: |
I can imagine this will mess up integration tests where you want to render an app, tear it down, and then do it again. |
@hendrikcech I removed the `invariant |
@hendrikcech Oops. Sent too soon. I removed the |
Sorry, I phrased that badly. What I meant was that the bug first showed there because the check was removed. Rendering a component multiple times to the same element should be supported. I couldn't nail down the issue yet but have a theory. Maybe not the constructor of the active route is passed in props.activeRoute but the mounted instance. Like in this example. |
@hendrikcech We have deprecated/removed our own custom version of Can you confirm/deny? |
Unfortunately this doesn't solve the problem. I have no clue where the bug originates from. |
@hendrikcech What does the code look like that you're using to test the issue with version 0.2.0? |
@mjackson I'm this using this code: var React = require('react')
var Route = require('react-nested-router').Route
var App = React.createClass({
render: function() {
console.log('render app')
return (
<div>
<h1>App: {Date.now()}</h1>
{this.props.activeRoute}
</div>
)
}
})
var Index = React.createClass({
render: function() {
console.log('render index')
return <span>Index: {Date.now()}</span>
}
})
var router = (
<Route handler={App}>
<Route name='index' path='/' handler={Index} />
</Route>
)
setInterval(function() {
React.renderComponent(router, document.body)
}, 1000) The router doesn't work well with jsfiddle, otherwise I would have put it up there. |
I haven't read the source enough to know if this is the case, but if you're passing the same descriptor then React will skip reconciliation altogether. If you recreate the descriptor (with a new props object, even if the props are all the same) it'll redo the reconciliation. |
@spicyj That was my first guess as well. However, as far as I can tell, the descriptor is recreated each time. |
@hendrikcech That code runs each time a route's props are recalculated. However, in your example code the route never changes, so props remain the same. You're re-using the same descriptor for your top-level |
@mjackson I didn't realize that. Recalculating a route's props on each render call fixes the issue. I got the example working by changing the render function in render: function () {
var path = URLStore.getCurrentPath();
var nextMatches = this.match(path);
var query = Path.extractQuery(path) || {};
var handlerProps = computeHandlerProps(nextMatches, query);
return this.props.handler(handlerProps);
} You may be able to find a smarter way to do this. I'm not sure if this raises new problems. |
I think the core issue here may be that you're used to creating descriptors inside a Another way to get your example to work (untested) may be to do something like this: function getRoutes() {
return <Route ... />;
}
setInterval(function() {
React.renderComponent(getRoutes(), document.body)
}, 1000) This way you'll be passing a new descriptor to |
@mjackson That doesn't work. The state of the root |
@hendrikcech Does this commit fix this issue? Instead of hanging onto a handler's props in between invocations of |
@mjackson Nice, the example works with the latest commit. Thanks! |
@hendrikcech Glad we got it fixed. Thanks for following up! |
Hey, I've encountered a bug while using this library and attached a failing test case.
It seems like the props.activeRoute component is not re-rendered when calling
router.renderComponent()
.The first render call behaves correctly. After that I expect
'render index'
and'render app'
to be logged every second. Instead onlyrender index
appears. The timestamp doesn't change either.I'm not really sure where to start looking for the bug. Maybe you could give me a hint?
The text was updated successfully, but these errors were encountered: