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

Fix #3648: observableRequiresReaction/computedRequiresReaction shouldn't warn with enableStaticRendering(true) #3649

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

urugator
Copy link
Collaborator

@urugator urugator commented Mar 7, 2023

Fixes #3648
Changed computedRequiresReaction to respect globalState.allowStateReads.

@changeset-bot
Copy link

changeset-bot bot commented Mar 7, 2023

🦋 Changeset detected

Latest commit: 2a6190b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
mobx-react Patch
mobx-react-lite Patch
mobx Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@urugator
Copy link
Collaborator Author

urugator commented Mar 7, 2023

Hm seems it's gonna be tricker in relation to computedRequiresReaction

@urugator
Copy link
Collaborator Author

urugator commented Mar 7, 2023

Why allowStateReads is se to true by default?
https://github.com/mobxjs/mobx/blob/main/packages/mobx/src/core/globalstate.ts#L95
that doesn't seem correct...

@urugator urugator requested a review from mweststrate March 8, 2023 14:42
Copy link
Member

@mweststrate mweststrate left a comment

Choose a reason for hiding this comment

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

Looking mostly ok! Left some questions

packages/mobx-react-lite/src/observer.ts Show resolved Hide resolved
expect(container).toHaveTextContent("0")
unmount()

expect(consoleWarnMock).toMatchSnapshot()
Copy link
Member

Choose a reason for hiding this comment

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

See previous comment

packages/mobx-react/src/observerClass.ts Outdated Show resolved Hide resolved
*/
allowStateReads = true
allowStateReads = false
Copy link
Member

Choose a reason for hiding this comment

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

This might be a breaking change? By default we allow state reads outside reactive contexts?

Copy link
Collaborator Author

@urugator urugator Mar 19, 2023

Choose a reason for hiding this comment

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

No. These flags, allowStateReads and allowStateChanges, says whether you're in a context, where reads/changes are allowed - or perhaps better - where they are supposed to take place. They're basically inDerivation/inAction flags - they're switched on/off when entering/leaving these, regardless of whether it should warn or not. We use these flags instead of directly checking for action/derivation, because the mapping isn't always exactly 1:1. But really the point is to demark these places, not to directly control the warning - the warning is always only raised in combination with requiresReaction/enforceAction. They should always start as false, because there is no running action/derivation by default.

Copy link
Member

Choose a reason for hiding this comment

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

Check, that adds up. I haven't been working on this for too long 😅.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Turns out it's more complicated. I think it was originally designed as described, but it was maybe misunderstood and changed with the introduction of autoAction.
The thing is that autoAction is supposed to warn when you modify state inside derivation, regardless of enforceAction configuration. So autoAction assumes that if allowStateChanges is false, there will be a warning when setting state, no other conditions needed.
In order for this to work the configure/resetGlobalState was updated to synchronize allowStateChanges with enforeAction configuration.
But the actual check for the warning doesn't assume this behavior:

if (
!globalState.allowStateChanges &&
(hasObservers || globalState.enforceActions === "always")
) {

Notice there is a bug - the check doesn't respect enforceActions: "never" (enforceActions === false).
This bug is actually a reason why the test for autoAction warning is passing - there is a test above that calls mobx.configure({ enforceActions: "never" }).
If you fix this bug, the autoAction warning (Side effects like changing state are not allowed) can never occur.

Copy link
Member

@mweststrate mweststrate left a comment

Choose a reason for hiding this comment

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

LGTM

@mweststrate
Copy link
Member

Needs rebase

@heath-freenome
Copy link

@urugator I'm still waiting for this. Can you rebase and merge?

@urugator
Copy link
Collaborator Author

Will try to take a look over the weekend. It will require some adaptation to the reworked observers.

@urugator
Copy link
Collaborator Author

urugator commented Oct 28, 2023

Update: I've spent a whole day on this, I've been dealing with some unanticipated issues. It might be possible to resolve your issue without bothering about these, not sure atm. If/when I find some more time I will try to focus on that. If you wanna give it a try, just revert the last commit (checkpoint) and go from that (don't push to this PR pls). IIRC there were tests failing on warning, because there is a test above that calls configure(...), but doesn't reset this configuration, otherwise it was good I think. EDIT: see update below

@@ -295,27 +296,6 @@ test("issue 12", () => {
expect(events).toEqual(["table", "row: coffee", "row: tea", "table", "row: soup"])
})

test("changing state in render should fail", () => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This test is wrong on multiple levels:
I don't recall changing state in render should ever throw, with a slight exception of autoAction, which doesn't work ATM as mentioned elsewhere.
It doesn't expect(...).toThrow(), it just checks for the error (that is never thrown).
If it's about enforceAction, it should expect console.warn instead of an error.
It pollutes console with Warning: Cannot update a component while rendering a different component (this is a bit surprising given that only one component is involved, but not a concern atm).

@urugator
Copy link
Collaborator Author

Update: Should be ready for re-review + merge and we may tackle the other issues elsewhere.

@urugator urugator requested a review from mweststrate October 29, 2023 10:17
@heath-freenome
Copy link

I'm curious why this MR hasn't been merged?

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

Successfully merging this pull request may close these issues.

using enableStaticRender() on the server causes "read outside a reactive context" warnings on server
3 participants