-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Reintroduce observable state,props,context in mobx-react #3863
Open
jzhan-canva
wants to merge
6
commits into
mobxjs:main
Choose a base branch
from
jzhan-canva:mobx-react-observable-props
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
a38b459
reintroduce observable state,props,context
jzhan-canva 617bb35
test and readme
jzhan-canva af3d709
Create bright-hornets-listen.md
jzhan-canva 7299b08
add tests back
jzhan-canva 6ff48f3
add test
jzhan-canva 3a8c951
add shouldReportChanged
jzhan-canva File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"mobx-react": patch | ||
--- | ||
|
||
Reintroduce observable state,props,context in mobx-react |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import React from "react" | ||
import { observer } from "../src" | ||
import { render, act } from "@testing-library/react" | ||
|
||
/** | ||
* some test suite is too tedious | ||
*/ | ||
|
||
afterEach(() => { | ||
jest.useRealTimers() | ||
}) | ||
|
||
// let consoleWarnMock: jest.SpyInstance | undefined | ||
// afterEach(() => { | ||
// consoleWarnMock?.mockRestore() | ||
// }) | ||
|
||
test("TODO", async () => { | ||
let renderCount = 0 | ||
const Child = observer(function Child({ children }) { | ||
renderCount++ | ||
// Accesses Parent's this.props | ||
return children() | ||
}) | ||
|
||
@observer | ||
class Parent extends React.Component<any> { | ||
// intentionally stable, so test breaks when you disable observable props (comment line 239 in observerClass) | ||
renderCallback = () => { | ||
return this.props.x | ||
} | ||
render() { | ||
// Access observable props as part of child | ||
return <Child>{this.renderCallback}</Child> | ||
} | ||
} | ||
|
||
function Root() { | ||
const [x, setX] = React.useState(0) | ||
// Send new props to Parent | ||
return ( | ||
<div onClick={() => setX(x => x + 1)}> | ||
<Parent x={x} /> | ||
</div> | ||
) | ||
} | ||
|
||
const app = <Root /> | ||
|
||
const { unmount, container } = render(app) | ||
|
||
expect(container).toHaveTextContent("0") | ||
expect(renderCount).toBe(1) | ||
|
||
await new Promise(resolve => setTimeout(() => resolve(null), 1000)) | ||
act(() => { | ||
console.log("changing state") | ||
container.querySelector("div")?.click() | ||
}) | ||
expect(container).toHaveTextContent("1") | ||
expect(renderCount).toBe(2) | ||
unmount() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be 1. The actual number isn't super relevant, it can depend on some React batching implementation details.
The point is that we must not issue an update on ANY component, when a component is already updating.
We use
isUpdating
flag to prevent updating self, but we must avoid callingforceUpdate
also on other components - in this case on Child component, which is subscribed toParent.props
, because we leakedParent.props
toChild
via callback.It's like calling
childRef.forceUpdate()
during Parent's render. We must not do that. It's an oversight in the original implementation. Once component is updating (Parent recieved new props) the only proper way to propagate change to Child is via props. This would normally happen if you would create the callback during render.The test was supposed to demonstrate that while this behavior is not correct, there is this unintended "feature" that you can send the same callback ref and still get the update (which is not supposed to happen with
memo
).So to fix this, we probably just need to make
isUpdating
flag global.Another way to put it is, that
props
must be observable for every derivation, except forobserver
derivation - that is any user definedcomputed
/reaction
/autorun
.Hope it's a bit clearer now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a bit less obvious example of usage that will break once it's fixed:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@urugator I see what you mean now
yes this is an unintended "feature" that let child display "correct" value, therefore I feel removing it will cause unexpected issue in our fairly large codebase
This is something I can do, as per this commit, I can change
globalState.trackingDerivation
to be an array, and addisReactObserver
(name TBD) toIDerivation
Eventually, during props' get method, I can check if other react observer is tracking it and show a error in console