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

Trigger a proper no-op warning for async state changes on server #7127

Merged
merged 1 commit into from
Jul 4, 2016
Merged

Trigger a proper no-op warning for async state changes on server #7127

merged 1 commit into from
Jul 4, 2016

Conversation

rricard
Copy link
Contributor

@rricard rricard commented Jun 27, 2016

This commit fixes #5473: ReactDOMServer.renderToString: presence of onClick
handler causes errors on async update

This commit performs the following changes:

  • Adds a getUpdateQueue method to ReactServerRenderingTransaction,
    ReactReconcileTransaction, ReactNativeReconcileTransaction and
    ReactTestReconcileTransaction
  • Make the ReactCompositeComponent call this getUpdateQueue instead of using
    ReactUpdateQueue that was unwanted at certain moments on server
  • On ReactServerRenderingTransaction, dispatch ReactUpdateQueue's methods
    while rendering and ReactNoopUpdateQueue's methods afterwards
  • Added a test that mimics the case presented in ReactDOMServer.renderToString: presence of onClick handler causes errors on async update #5473 with setState and
    replaceState

}, this)
.reduce(function(ReactUpdate, funcObj) {
return Object.assign(ReactUpdate, funcObj);
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure about this though, maybe there is a way to do better there. I personally would have used Immutable for this kind of trick, but, I understand the constraints here. So if I can do that differently, just tell me!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you please unwind this to be simple (repetitive) code instead? IMO meta programming is not worth it here :-)

Copy link
Collaborator

@gaearon gaearon Jun 27, 2016

Choose a reason for hiding this comment

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

Do I understand correctly that the intention is to use ReactUpdateQueue during mounting so initial setState works but switch it out right after the mounting is over?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We would also need a test for forceUpdate.

Copy link
Contributor Author

@rricard rricard Jun 27, 2016

Choose a reason for hiding this comment

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

I can do that, especially if I can consider that UpdateQueues will be identical. Yes, you understood that correctly, should I change my comment to be more clear maybe ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It will be more obvious after the unwinding.

@@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactReconcileTransaction
* @flow weak
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh! maybe you don't want those! Can delete them if you ask, but flow helped me though (once again!)...

Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be possible to add any type annotations if you're already using flow? I know there have been some recent efforts by @vjeux to add annotations. I don't see any files that are using weak mode either so that might be something to consider.

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 can totally do that! I wasn't sure about babel on the React codebase but as @gaearon pointed out, babel is there so, yes I can do it. (After this, I can also start to add some flow throughout the codebase if you are ok with that, you can even point me to critical parts. However, the flow declarations for react already are super complete, so I'm not sure there is really critical parts).

Copy link
Contributor

Choose a reason for hiding this comment

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

I have no idea what flow weak does, can you educate me? Also what isn't working with normal flow?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is 53 flow errors in ReactCompositeComponent (missing annotations), I'll do this file in a separate PR.

Copy link
Contributor Author

@rricard rricard Jun 27, 2016

Choose a reason for hiding this comment

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

weak allows unannotated function defs, it is often used for progressive addition of flow, that way you can start typechecking but in the absence of annotation, flow will consider the params automatically as any. https://flowtype.org/docs/existing.html#weak-mode

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 instance, I think you could add @flow weak everywhere in this codebase without raising much issues. The upside would be that flow could still emit warnings on very risky things it managed to infer.

@rricard
Copy link
Contributor Author

rricard commented Jun 27, 2016

Still working on it, don't trust the bot ! I will rebase/squash at the end don't worry !

@rricard
Copy link
Contributor Author

rricard commented Jun 27, 2016

@gaearon: took your comments into consideration and rebased/squashed the changes.

@rricard rricard changed the title Trigger a proper no-op warning on async setState on server Trigger a proper no-op warning for async state changes on server Jun 27, 2016
// We use a ReactNoopUpdateQueue that switches to ReactUpdateQueue while
// mounting
var transaction = this;
return {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This allocates an object any time getUpdateQueue is called. Instead, it should only be initialized once. For example, you could write a class called ReactServerUpdateQueue that would take transaction as a constructor argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, good catch! I will refactor that!

'Warning: setState(...): Can only update a mounted or mounting' +
' component. This usually means you called setState() on an' +
' unmounted component. This is a no-op. Please check the code for' +
' the Component component.'
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 would actually change the message to something more adapted to the server:
Warning: setState(...): Can only update a mounting component. This usually means you called setState() on an unmounted component or already mounted component on a server. This is a no-op. Please check the code for the Component component.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree (if it’s not super difficult). Note that server has no concept of “already mounted component”. I would say “This usually means you called setState() outside componentWillMount() on the server.” or something like this.

Copy link
Contributor Author

@rricard rricard Jun 27, 2016

Choose a reason for hiding this comment

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

I'll think of something. I really like react warnings because they are super-clear, I want to continue in this direction here...

@rricard
Copy link
Contributor Author

rricard commented Jun 27, 2016

Finishing with this and squashing/rebasing then

@rricard
Copy link
Contributor Author

rricard commented Jun 27, 2016

Again, don't trust the bot, still needs revision!

@gaearon
Copy link
Collaborator

gaearon commented Jun 30, 2016

Thanks!

@rricard
Copy link
Contributor Author

rricard commented Jun 30, 2016

No problem, I was going to do a second PR for that afterwards but I can do that just now!

@rricard
Copy link
Contributor Author

rricard commented Jun 30, 2016

Ok, I will need some time to do that ... I need to go deep sometimes...

@rricard
Copy link
Contributor Author

rricard commented Jun 30, 2016

Ok so I'll just remove some annotations here so we can merge it. Still, I'll stash my work to continue that afterwards!

@rricard
Copy link
Contributor Author

rricard commented Jun 30, 2016

@gaearon so I only left the flow typecheck in ReactServerUpdateQueue. I think it's mergeable now. I'll continue with flow in other PRs!

@@ -30,10 +31,11 @@ var noopCallbackQueue = {
* @class ReactServerRenderingTransaction
* @param {boolean} renderToStaticMarkup
*/
function ReactServerRenderingTransaction(renderToStaticMarkup) {
function ReactServerRenderingTransaction(renderToStaticMarkup: boolean) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: : boolean is now unnecessary here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep

This commit fixes #5473: ReactDOMServer.renderToString: presence of onClick
handler causes errors on async update

This commit performs the following changes:

- Adds a getUpdateQueue method to ReactServerRenderingTransaction,
  ReactReconcileTransaction, ReactNativeReconcileTransaction and
  ReactTestReconcileTransaction
- Make the ReactCompositeComponent call this getUpdateQueue instead of using
  ReactUpdateQueue that was unwanted at certain moments on server
- On ReactServerRenderingTransaction, dispatch ReactUpdateQueue's methods
  while rendering and warning methods afterwards. This is done through the new
  ReactServerUpdateQueue class
- Added a series of tests that mimics the case presented in #5473 with setState,
  forceUpdate and replaceState
- Add flow typechecking on concerned files
@gaearon gaearon added this to the 15-next milestone Jul 4, 2016
@gaearon gaearon merged commit dbdddf1 into facebook:master Jul 4, 2016
@gaearon
Copy link
Collaborator

gaearon commented Jul 4, 2016

Thanks!

gaearon added a commit that referenced this pull request Jul 4, 2016
It was added in #7127 but this file isn’t type checked anyway.
@rricard rricard deleted the fix-5473 branch July 4, 2016 15:01
@rricard
Copy link
Contributor Author

rricard commented Jul 4, 2016

Thank you for reviewing me. That was a good and instructive experience!

zpao pushed a commit that referenced this pull request Jul 8, 2016
This commit fixes #5473: ReactDOMServer.renderToString: presence of onClick
handler causes errors on async update

This commit performs the following changes:

- Adds a getUpdateQueue method to ReactServerRenderingTransaction,
  ReactReconcileTransaction, ReactNativeReconcileTransaction and
  ReactTestReconcileTransaction
- Make the ReactCompositeComponent call this getUpdateQueue instead of using
  ReactUpdateQueue that was unwanted at certain moments on server
- On ReactServerRenderingTransaction, dispatch ReactUpdateQueue's methods
  while rendering and warning methods afterwards. This is done through the new
  ReactServerUpdateQueue class
- Added a series of tests that mimics the case presented in #5473 with setState,
  forceUpdate and replaceState
- Add flow typechecking on concerned files
(cherry picked from commit dbdddf1)
@zpao zpao modified the milestones: 15-next, 15.2.1 Jul 8, 2016
usmanajmal pushed a commit to usmanajmal/react that referenced this pull request Jul 11, 2016
…ebook#7127)

This commit fixes facebook#5473: ReactDOMServer.renderToString: presence of onClick
handler causes errors on async update

This commit performs the following changes:

- Adds a getUpdateQueue method to ReactServerRenderingTransaction,
  ReactReconcileTransaction, ReactNativeReconcileTransaction and
  ReactTestReconcileTransaction
- Make the ReactCompositeComponent call this getUpdateQueue instead of using
  ReactUpdateQueue that was unwanted at certain moments on server
- On ReactServerRenderingTransaction, dispatch ReactUpdateQueue's methods
  while rendering and warning methods afterwards. This is done through the new
  ReactServerUpdateQueue class
- Added a series of tests that mimics the case presented in facebook#5473 with setState,
  forceUpdate and replaceState
- Add flow typechecking on concerned files
usmanajmal pushed a commit to usmanajmal/react that referenced this pull request Jul 11, 2016
It was added in facebook#7127 but this file isn’t type checked anyway.
@graue
Copy link
Contributor

graue commented Nov 22, 2016

Looks like this was actually a breaking change. It broke some previously working setState calls.

@gaearon
Copy link
Collaborator

gaearon commented Nov 22, 2016

Can you file an issue and provide code reproducing it? setState calls while rendering is in progress should still work. After mounting is over they should become no-ops instead of throwing like before. What kind of calls are breaking?

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.

ReactDOMServer.renderToString: presence of onClick handler causes errors on async update
6 participants