1414
1515import type { ReactCoroutine } from 'ReactCoroutine' ;
1616import type { Fiber } from 'ReactFiber' ;
17+ import type { FiberRoot } from 'ReactFiberRoot' ;
1718import type { HostConfig } from 'ReactFiberReconciler' ;
19+ import type { Scheduler } from 'ReactFiberScheduler' ;
20+ import type { PriorityLevel } from 'ReactPriorityLevel' ;
1821
1922var { reconcileChildFibers } = require ( 'ReactChildFiber' ) ;
23+ var { LowPriority } = require ( 'ReactPriorityLevel' ) ;
2024var ReactTypeOfWork = require ( 'ReactTypeOfWork' ) ;
2125var {
2226 IndeterminateComponent,
3438} = require ( 'ReactPriorityLevel' ) ;
3539var { findNextUnitOfWorkAtPriority } = require ( 'ReactFiberPendingWork' ) ;
3640
37- module . exports = function < T , P , I , C > ( config : HostConfig < T , P , I , C > ) {
38-
41+ module . exports = function < T , P , I , C > ( config : HostConfig < T , P , I , C > , getScheduler : ( ) = > Scheduler ) {
3942 function reconcileChildren ( current , workInProgress , nextChildren ) {
4043 const priority = workInProgress . pendingWorkPriority ;
4144 workInProgress . child = reconcileChildFibers (
@@ -54,31 +57,88 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
5457 workInProgress . pendingWorkPriority = NoWork ;
5558 }
5659
60+ function updateFiber ( fiber : Fiber , state : any , priorityLevel : PriorityLevel ) : void {
61+ const { scheduleLowPriWork } = getScheduler ( ) ;
62+ fiber . pendingState = state ;
63+
64+ while ( true ) {
65+ if ( fiber . pendingWorkPriority === NoWork ||
66+ fiber . pendingWorkPriority >= priorityLevel ) {
67+ fiber . pendingWorkPriority = priorityLevel ;
68+ }
69+ // Duck type root
70+ if ( fiber . stateNode && fiber . stateNode . containerInfo ) {
71+ const root : FiberRoot = ( fiber . stateNode : any ) ;
72+ scheduleLowPriWork ( root , priorityLevel ) ;
73+ return ;
74+ }
75+ if ( ! fiber . return ) {
76+ throw new Error ( 'No root!' ) ;
77+ }
78+ fiber = fiber . return ;
79+ }
80+ }
81+
82+ // Class component state updater
83+ const updater = {
84+ enqueueSetState ( instance , partialState ) {
85+ const fiber = instance . _fiber ;
86+
87+ const prevState = fiber . pendingState || fiber . memoizedState ;
88+ const state = Object . assign ( { } , prevState , partialState ) ;
89+
90+ // Must schedule an update on both alternates, because we don't know tree
91+ // is current.
92+ updateFiber ( fiber , state , LowPriority ) ;
93+ if ( fiber . alternate ) {
94+ updateFiber ( fiber . alternate , state , LowPriority ) ;
95+ }
96+ } ,
97+ } ;
98+
5799 function updateClassComponent ( current : ?Fiber , workInProgress : Fiber ) {
100+ // A class component update is the result of either new props or new state.
101+ // Account for the possibly of missing pending props or state by falling
102+ // back to the most recent props or state.
58103 var props = workInProgress . pendingProps ;
104+ var state = workInProgress . pendingState ;
105+ if ( ! props && current ) {
106+ props = current . memoizedProps ;
107+ }
108+ if ( ! state && current ) {
109+ state = current . memoizedState ;
110+ }
111+
59112 var instance = workInProgress . stateNode ;
60113 if ( ! instance ) {
61114 var ctor = workInProgress . type ;
62115 workInProgress . stateNode = instance = new ctor ( props ) ;
116+ state = workInProgress . pendingState = instance . state || null ;
117+ // The instance needs access to the fiber so that it can schedule updates
118+ instance . _fiber = workInProgress ;
119+ instance . updater = updater ;
63120 } else if ( typeof instance . shouldComponentUpdate === 'function' ) {
64121 if ( current && current . memoizedProps ) {
65- // Revert to the last flushed props, incase we aborted an update.
122+ // Revert to the last flushed props and state , incase we aborted an update.
66123 instance . props = current . memoizedProps ;
67- if ( ! instance . shouldComponentUpdate ( props ) ) {
124+ instance . state = current . memoizedState ;
125+ if ( ! instance . shouldComponentUpdate ( props , state ) ) {
68126 return bailoutOnCurrent ( current , workInProgress ) ;
69127 }
70128 }
71129 if ( ! workInProgress . hasWorkInProgress && workInProgress . memoizedProps ) {
72- // Reset the props, in case this is a ping-pong case rather than a
73- // completed update case. For the completed update case, the instance
74- // props will already be the memoizedProps .
130+ // Reset the props and state , in case this is a ping-pong case rather
131+ // than a completed update case. For the completed update case, the
132+ // instance props and state will already be the memoized props and state .
75133 instance . props = workInProgress . memoizedProps ;
76- if ( ! instance . shouldComponentUpdate ( props ) ) {
134+ instance . state = workInProgress . memoizedState ;
135+ if ( ! instance . shouldComponentUpdate ( props , state ) ) {
77136 return bailoutOnAlreadyFinishedWork ( workInProgress ) ;
78137 }
79138 }
80139 }
81140 instance . props = props ;
141+ instance . state = state ;
82142 var nextChildren = instance . render ( ) ;
83143 reconcileChildren ( current , workInProgress , nextChildren ) ;
84144 workInProgress . pendingWorkPriority = NoWork ;
@@ -188,9 +248,11 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
188248 // the same props as the new one. In that case, we can just copy the output
189249 // and children from that node.
190250 workInProgress . memoizedProps = workInProgress . pendingProps ;
251+ workInProgress . memoizedState = workInProgress . pendingState ;
191252 workInProgress . output = current . output ;
192253 const priorityLevel = workInProgress . pendingWorkPriority ;
193254 workInProgress . pendingProps = null ;
255+ workInProgress . pendingState = current . pendingState = null ;
194256 workInProgress . pendingWorkPriority = NoWork ;
195257 workInProgress . stateNode = current . stateNode ;
196258 if ( current . child ) {
@@ -219,6 +281,10 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
219281 // looking for. In that case, we should be able to just bail out.
220282 const priorityLevel = workInProgress . pendingWorkPriority ;
221283 workInProgress . pendingProps = null ;
284+ workInProgress . pendingState = null ;
285+ if ( workInProgress . alternate ) {
286+ workInProgress . alternate . pendingState = null ;
287+ }
222288 workInProgress . pendingWorkPriority = NoWork ;
223289
224290 workInProgress . firstEffect = null ;
@@ -252,12 +318,17 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
252318 // Ideally nothing should rely on this, but relying on it here
253319 // means that we don't need an additional field on the work in
254320 // progress.
255- if ( current && workInProgress . pendingProps === current . memoizedProps ) {
321+ if ( current &&
322+ workInProgress . pendingProps === current . memoizedProps &&
323+ workInProgress . pendingState === current . memoizedState
324+ ) {
256325 return bailoutOnCurrent ( current , workInProgress ) ;
257326 }
258327
259328 if ( ! workInProgress . hasWorkInProgress &&
260- workInProgress . pendingProps === workInProgress . memoizedProps ) {
329+ workInProgress . pendingProps === workInProgress . memoizedProps &&
330+ workInProgress . pendingState === workInProgress . memoizedState
331+ ) {
261332 return bailoutOnAlreadyFinishedWork ( workInProgress ) ;
262333 }
263334
0 commit comments