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

Document legacyness of the return value of ReactDOM.render() #6400

Merged
merged 1 commit into from
Apr 7, 2016

Conversation

jimfb
Copy link
Contributor

@jimfb jimfb commented Apr 1, 2016

Document legacyness of the return value of ReactDOM.render(), as per #6397

>
> `ReactDOM.render()` currently returns a reference to the root ReactComponent instance. However, using this return value is legacy
> and should be avoided. If you need a reference to the root ReactComponent instance, the preferred solution is to attach a
> [callback ref](/react/docs/more-about-refs.html#the-ref-callback-attribute) to the root element.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between a callback ref and the value provided to the optional callback function to ReactDOM.render?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the purposes of getting a reference to the root node, I think they're both semantically equivilant. The optional callback was introduced before callback refs were a thing. For consistency, I think we would want to teach refs as the standard way of getting a reference to an instance.

However, callback refs and the optional callback are not identical with regards to their other semantics. The optional callback will be fired when the render completes, whereas the callback ref will only be fired when a component mounts/unmounts. So their behavior is the same for initial mount, but different for updates. Realistically, now that we have callback refs, the optional callback probably isn't very useful, but there are still some potential use cases if you wanted to know when a particular update/render has fully completed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation, @jimfb.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a small example here. Like this:

// Before:
var instance = ReactDOM.render(<App />, rootEl);
doSomethingWithInstance(instance);

// After:
ReactDOM.render(<App ref={doSomethingWithInstance} />, rootEl);

@jimfb
Copy link
Contributor Author

jimfb commented Apr 6, 2016

Ping @gaearon @zpao Can one of you review this?

@@ -161,6 +161,10 @@ If the optional callback is provided, it will be executed after the component is
> `ReactDOM.render()` does not modify the container node (only modifies the children of the container). In
> the future, it may be possible to insert a component to an existing DOM node without overwriting
> the existing children.
>
> `ReactDOM.render()` currently returns a reference to the root ReactComponent instance. However, using this return value is legacy
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s put ReactComponent in backticks. I would also rephrase to clarify: "currently returns a reference to the root ReactComponent instance that was mounted as a result of this call."

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it’s good to explain why we ask people to change their code. I would change "using this return value is legacy" to "we are deprecating this way of accessing the root component instance because in the future React might render components asynchronously in some cases."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to use the word "deprecating" because we have a policy that we only mark something as "deprecated" when it's removal is imminent for the next release. But I do like your additional explanation, so I'll work that into the message.

@iamdustan
Copy link
Contributor

Would it be premature to add a rule for this to https://github.com/yannickcr/eslint-plugin-react/ start filtering this information out to the community?

@gaearon
Copy link
Collaborator

gaearon commented Apr 6, 2016

👍 I think it’s a good idea. This would be a breaking change for them tho? If it becomes a default. @iamdustan

@gaearon
Copy link
Collaborator

gaearon commented Apr 6, 2016

@jimfb I’m accepting on the condition you address the above comments. Thanks!

@jimfb jimfb merged commit 1dc7c58 into facebook:master Apr 7, 2016
zpao pushed a commit that referenced this pull request Apr 7, 2016
Document legacyness of the return value of ReactDOM.render()
(cherry picked from commit 1dc7c58)
@jeffbski
Copy link
Contributor

This should probably be considered along with ReactDOM.renderToString and ReactDOM.renderToStaticMarkup. Would those necessarily not be able to synchronously return the string markup too (assuming an async render is allowed)?

If that is true, then would they return a promise, observable, or use a new cb parameter to obtain the html?

So whatever is decided for those, maybe a similar mechanism should be allowed for ReactDOM.render for symmetry. Meaning if renderToString and renderToStaticMarkup both return a promise which eventually resolves to the html, maybe render should return a promise which eventually resolves to the component. Likewise if observable or cb mechanism is chosen. This is an alternative to using the ref cb.

It is nice to have symmetry as much as possible in these api's. Developers have enough other things to worry about.

@gaearon
Copy link
Collaborator

gaearon commented Apr 11, 2016

I think renderTo* methods would stay synchronous because they don’t have any updates. They are meant to be called as one-offs, rather then maintain continuously rendering UIs. On the other hand, ReactDOM.render() schedules a reconciliation that can be paused because other important work is happening (e.g. handling a gesture). Incremental reconciliation doesn’t really help on the server because you can’t just show “some parts” and later show “other parts”—once you send the response it’s too late, and in any case the network latency is much bigger than the rendering cost so you “drop frames” anyway.

@jimfb
Copy link
Contributor Author

jimfb commented Apr 11, 2016

@gaearon beat me to the punch. His answer is exactly correct. 👍

@jeffbski
Copy link
Contributor

ok, thanks. That answers my question.

iamdustan added a commit to iamdustan/eslint-plugin-react that referenced this pull request May 3, 2016
iamdustan added a commit to iamdustan/eslint-plugin-react that referenced this pull request May 3, 2016
iamdustan added a commit to iamdustan/eslint-plugin-react that referenced this pull request May 4, 2016
@iamdustan
Copy link
Contributor

A quick follow-up that a rule for this has landed in eslint-plugin-react. jsx-eslint/eslint-plugin-react#586

@taion
Copy link

taion commented Jan 7, 2018

In light of #11401, attaching a callback ref to the root component may cease to carry the desired semantics here.

As such, should the guidance instead be updated to be to use the callback from ReactDOM.render?

@gaearon
Copy link
Collaborator

gaearon commented Jan 7, 2018

Hmm could you clarify what would change?

@gaearon
Copy link
Collaborator

gaearon commented Jan 7, 2018

(To be clear I don't think there was a team consensus to implement #11401 specifically—it was just one of proposals and IMO a somewhat extreme one.)

@taion
Copy link

taion commented Jan 7, 2018

I mean "use the optional callback function to ReactDOM.render" instead of "attach a callback ref".

Though this problem would sort of go away if ReactDOM.render returned a promise or something ;)

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

Successfully merging this pull request may close these issues.

7 participants