facebookarchive / react-page

Easy Application Development with React JavaScript
Apache License 2.0
797 stars 72 forks source link

React needs a special code-path for reconciling different component types rendered into HTML element #32

Open andreypopp opened 11 years ago

andreypopp commented 11 years ago

Currently React blows away entire markup during reconciliation if prev and next components have different constructors. That's not good for components rendered directly into <html> element — for example if some stylesheets were removed and then appended during reconciliation — page would blink.

In react-app I solve this by declaring that pages are not components but specifications which are mounted into a single long-lived Page component which is responsible to delegate render() and other lifecycle calls to such specifications.

The requirement for such page specification is to always return <html> markup from a render() call.

This works well but creates an indirection layer where top-level components are not components but pages. I'd rather like them to be the same so I was wondering if it's possible to add a special code-path to react reconciliation mechanism for handling <html> element re-renders.

petehunt commented 11 years ago

What if instead you injected custom components for React.DOM.html, React.DOM.head and React.DOM.body that could do a limited set of custom actions? That is, you could have an implementation of React.DOM.head on the client that never re-renders directly, but looks at how its this.props.children changes and does custom DOM operations in componentDidUpadte().

andreypopp commented 11 years ago

@petehunt I thought of this but rather then doing things in componentDidUpdate I wanted to override updateComponent.

But it turns out it's not that easy — if we are happen to reconcile composite components which have different constructors and have React.DOM.{html,head} in this._renderedComponent (or even deep down in the composition hierarchy) then the reconciliation procedure will just prune the old tree and replace it with new markup.

So I'm thinking of the following:

andreypopp commented 11 years ago

@petehunt forget about all I said previously — I think it requires a lot of changes in React. I've "fixed" mutateHTMLNodeWithMarkup.jshttps://gist.github.com/andreypopp/7474901

Now it has mutateHEADNodeWithMarkup which updates head children without setting innerHTML and also prevents re-appending same <link> elements so they are not refetched and so there are no blinks in UI due to stylesheet update.

There's one problem — this all seems like a huuuge dirty hack... anyway, what do you think about this changeset?