-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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
Decouple update queue from Fiber type #12600
Conversation
6fdc713
to
9ae2db3
Compare
@@ -248,7 +248,7 @@ exports[`ReactDebugFiberPerf recovers from caught errors 1`] = ` | |||
⛔ (Committing Changes) Warning: Lifecycle hook scheduled a cascading update | |||
⚛ (Committing Snapshot Effects: 0 Total) | |||
⚛ (Committing Host Effects: 2 Total) | |||
⚛ (Calling Lifecycle Methods: 0 Total) | |||
⚛ (Calling Lifecycle Methods: 1 Total) |
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.
This is because we weren't counting componentDidCatch
as a lifecycle previously
ReactDOM: size: 🔺+0.4%, gzip: -0.2% Details of bundled changes.Comparing: 999b656...e4ce363 react-dom
react-art
react-test-renderer
react-reconciler
react-native-renderer
Generated by 🚫 dangerJS |
Need to add “update DevTools” to todos. I think it might rely on |
I don't think so? I don't see any references to |
Note: the bundle size changes are mostly because I haven't deleted the old update queue yet :D |
e325697
to
a99b4ca
Compare
@sebmarkbage Ready for review |
⚛ (Committing Host Effects: 1 Total) | ||
⚛ (Calling Lifecycle Methods: 1 Total) | ||
⚛ (Committing Host Effects: 0 Total) | ||
⚛ (Calling Lifecycle Methods: 0 Total) |
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.
I don't know why this wasn't already 0. There are no host effects or lifecycles in the second flush. New snapshot seems correct.
@@ -274,7 +274,7 @@ exports[`ReactDebugFiberPerf recovers from fatal errors 1`] = ` | |||
⚛ (Committing Changes) | |||
⚛ (Committing Snapshot Effects: 0 Total) | |||
⚛ (Committing Host Effects: 1 Total) | |||
⚛ (Calling Lifecycle Methods: 0 Total) | |||
⚛ (Calling Lifecycle Methods: 1 Total) |
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.
Same
Needless to say, this is a risky change. I'll do the next www sync and fix any bugs that may come up. |
What does [redacted] mean? |
@@ -749,10 +684,11 @@ export default function( | |||
): boolean { | |||
const ctor = workInProgress.type; | |||
const instance = workInProgress.stateNode; | |||
resetInputPointers(workInProgress, instance); |
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.
What is this change? You didn't replicate the other assignment so something is new.
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.
Object.assign(resultState, partialState); | ||
} | ||
|
||
function enqueueDerivedStateFromProps( |
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.
DRY for DRYness sake? Makes it harder to read this inline IMO. It also encourages reading the getDerivedStateFromProps property in multiple places if they're also needed at the callsite. Only abstract if it is chunk of work. (On the flip side, this PR successfully unabstract memoizeProps and memoizeState in places.)
if (updateQueue !== null && updateQueue.capturedValues !== null) { | ||
workInProgress.effectTag &= ~DidCapture; | ||
if (typeof instance.componentDidCatch === 'function') { | ||
workInProgress.effectTag |= ErrLog; |
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.
There was a reason we had to apply these effects in the complete phase. Why are we able to move them to the begin phase 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.
I don't think there was a reason. It happened to be a convenient place to do it. Now we do it while processing the update queue.
@@ -19,14 +19,14 @@ export const Update = /* */ 0b000000000100; | |||
export const PlacementAndUpdate = /* */ 0b000000000110; | |||
export const Deletion = /* */ 0b000000001000; | |||
export const ContentReset = /* */ 0b000000010000; | |||
export const Callback = /* */ 0b000000100000; | |||
export const UpdateQueue = /* */ 0b000000100000; |
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.
What are theses? They're not described in terms of side-effects. Either this needs to change, or the whole thing renamed.
const ClassUpdateQueue = 0; | ||
const RootUpdateQueue = 1; | ||
|
||
type UpdateShared<Payload, U> = { |
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.
I really had the term "Shared". This has been sneaking into RN too.
It doesn't describe anything about the concept other than DRYness which indicates that maybe you should repeat yourself. If it is real concept, name it.
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.
Stop denying me muh mixins!
type RootUpdateQueueType = UpdateQueueShared<RootUpdate, ReactNodeList>; | ||
|
||
type UpdateQueueOwner<Queue, State> = { | ||
alternate: UpdateQueueOwner<Queue> | null, |
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.
This is clearly not going to be how we describe "redacted" so seems like a too early abstraction. Even just assuming that it is a single argument is a big assumption. Just use Fiber until you have something else.
} | ||
// Clear the list of render phase updates. | ||
finishedQueue.firstRenderPhaseUpdate = finishedQueue.lastRenderPhaseUpdate = null; | ||
} |
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.
You are forking into a first class concept with typeOfUpdateQueue
then you're picking separate code paths again in commitEffect. The only thing gain by doing that instead of specializing each function is that you can reuse the code above here. Just break this out into a reusable function and instead specialize each code path without making typeOfUpdateQueue a first class thing.
TODO after chatting to @sebmarkbage:
|
995a437
to
73d4d48
Compare
The update queue is in need of a refactor. Recent bugfixes (facebook#12528) have exposed some flaws in how it's modeled. Upcoming features like Suspense and [redacted] also rely on the update queue in ways that weren't anticipated in the original design. Major changes: - Instead of boolean flags for `isReplace` and `isForceUpdate`, updates have a `tag` field (like Fiber). This lowers the cost for adding new types of updates. - Render phase updates are special cased. Updates scheduled during the render phase are dropped if the work-in-progress does not commit. This is used for `getDerivedStateFrom{Props,Catch}`. - `callbackList` has been replaced with a generic effect list. Aside from callbacks, this is also used for `componentDidCatch`.
73d4d48
to
8830fd2
Compare
I tried to avoid this at first, since we avoid it everywhere else in the Fiber codebase, but since updates are not in a hot path, the trade off with file size seems worth it.
The update queue is in need of a refactor. Recent bugfixes (#12528) have exposed some flaws in how it's modeled. Upcoming features like Suspense and [redacted] also rely on the update queue in ways that weren't anticipated in the original design.
Major changes:
isReplace
andisForceUpdate
, updates have atag
field (like Fiber). This lowers the cost for adding new types of updates.getDerivedStateFrom{Props,Catch}
.callbackList
has been replaced with a generic effect list. Aside from callbacks, this is also used forcomponentDidCatch
.TODO:
Update React DevTools dependency onI reverted this changehasForceUpdate
(in a separate repo)