5555 OffscreenPriority,
5656} = require ( 'ReactPriorityLevel' ) ;
5757var {
58- Update,
5958 Placement,
6059 ContentReset,
6160 Err,
@@ -91,7 +90,12 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
9190 mountClassInstance,
9291 resumeMountClassInstance,
9392 updateClassInstance,
94- } = ReactFiberClassComponent ( scheduleUpdate , getPriorityContext ) ;
93+ } = ReactFiberClassComponent (
94+ scheduleUpdate ,
95+ getPriorityContext ,
96+ memoizeProps ,
97+ memoizeState ,
98+ ) ;
9599
96100 function markChildAsProgressed ( current , workInProgress , priorityLevel ) {
97101 // We now have clones. Let's store them as the currently progressed work.
@@ -176,12 +180,13 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
176180 // Normally we can bail out on props equality but if context has changed
177181 // we don't do the bailout and we have to reuse existing props instead.
178182 if ( nextChildren === null ) {
179- nextChildren = current && current . memoizedProps ;
183+ nextChildren = workInProgress . memoizedProps ;
180184 }
181185 } else if ( nextChildren === null || workInProgress . memoizedProps === nextChildren ) {
182186 return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
183187 }
184188 reconcileChildren ( current , workInProgress , nextChildren ) ;
189+ memoizeProps ( workInProgress , nextChildren ) ;
185190 return workInProgress . child ;
186191 }
187192
@@ -202,16 +207,20 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
202207 // Normally we can bail out on props equality but if context has changed
203208 // we don't do the bailout and we have to reuse existing props instead.
204209 if ( nextProps === null ) {
205- nextProps = current && current . memoizedProps ;
210+ nextProps = memoizedProps ;
211+ }
212+ } else {
213+ if ( nextProps == null || memoizedProps === nextProps ) {
214+ return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
215+ }
216+ // TODO: Disable this before release, since it is not part of the public API
217+ // I use this for testing to compare the relative overhead of classes.
218+ if ( typeof fn . shouldComponentUpdate === 'function' &&
219+ ! fn . shouldComponentUpdate ( memoizedProps , nextProps ) ) {
220+ // Memoize props even if shouldComponentUpdate returns false
221+ memoizeProps ( workInProgress , nextProps ) ;
222+ return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
206223 }
207- } else if ( nextProps === null || memoizedProps === nextProps || (
208- // TODO: Disable this before release, since it is not part of the public API
209- // I use this for testing to compare the relative overhead of classes.
210- memoizedProps !== null &&
211- typeof fn . shouldComponentUpdate === 'function' &&
212- ! fn . shouldComponentUpdate ( memoizedProps , nextProps )
213- ) ) {
214- return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
215224 }
216225
217226 var unmaskedContext = getUnmaskedContext ( workInProgress ) ;
@@ -226,6 +235,7 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
226235 nextChildren = fn ( nextProps , context ) ;
227236 }
228237 reconcileChildren ( current , workInProgress , nextChildren ) ;
238+ memoizeProps ( workInProgress , nextProps ) ;
229239 return workInProgress . child ;
230240 }
231241
@@ -258,31 +268,23 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
258268 shouldUpdate : boolean ,
259269 hasContext : boolean ,
260270 ) {
261- // Schedule side-effects
262-
263271 // Refs should update even if shouldComponentUpdate returns false
264272 markRef ( current , workInProgress ) ;
265273
266- if ( shouldUpdate ) {
267- workInProgress . effectTag |= Update ;
268- } else {
269- // If an update was already in progress, we should schedule an Update
270- // effect even though we're bailing out, so that cWU/cDU are called.
271- if ( current ) {
272- const instance = current . stateNode ;
273- if ( instance . props !== current . memoizedProps ||
274- instance . state !== current . memoizedState ) {
275- workInProgress . effectTag |= Update ;
276- }
277- }
274+ if ( ! shouldUpdate ) {
278275 return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
279276 }
280277
281- // Rerender
282278 const instance = workInProgress . stateNode ;
279+
280+ // Rerender
283281 ReactCurrentOwner . current = workInProgress ;
284282 const nextChildren = instance . render ( ) ;
285283 reconcileChildren ( current , workInProgress , nextChildren ) ;
284+ // Memoize props and state using the values we just used to render.
285+ // TODO: Restructure so we never read values from the instance.
286+ memoizeState ( workInProgress , instance . state ) ;
287+ memoizeProps ( workInProgress , instance . props ) ;
286288
287289 // The context might have changed so we need to recalculate it.
288290 if ( hasContext ) {
@@ -321,7 +323,7 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
321323 }
322324 const element = state . element ;
323325 reconcileChildren ( current , workInProgress , element ) ;
324- workInProgress . memoizedState = state ;
326+ memoizeState ( workInProgress , state ) ;
325327 return workInProgress . child ;
326328 }
327329 // If there is no update queue, that's a bailout because the root has no props.
@@ -338,7 +340,7 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
338340 // Normally we can bail out on props equality but if context has changed
339341 // we don't do the bailout and we have to reuse existing props instead.
340342 if ( nextProps === null ) {
341- nextProps = prevProps ;
343+ nextProps = memoizedProps ;
342344 if ( ! nextProps ) {
343345 throw new Error ( 'We should always have pending or current props.' ) ;
344346 }
@@ -403,6 +405,7 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
403405
404406 // Reconcile the children and stash them for later work.
405407 reconcileChildrenAtPriority ( current , workInProgress , nextChildren , OffscreenPriority ) ;
408+ memoizeProps ( workInProgress , nextProps ) ;
406409 workInProgress . child = current ? current . child : null ;
407410
408411 if ( ! current ) {
@@ -422,10 +425,22 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
422425 return null ;
423426 } else {
424427 reconcileChildren ( current , workInProgress , nextChildren ) ;
428+ memoizeProps ( workInProgress , nextProps ) ;
425429 return workInProgress . child ;
426430 }
427431 }
428432
433+ function updateHostText ( current , workInProgress ) {
434+ let nextProps = workInProgress . pendingProps ;
435+ if ( nextProps === null ) {
436+ nextProps = workInProgress . memoizedProps ;
437+ }
438+ memoizeProps ( workInProgress , nextProps ) ;
439+ // Nothing to do here. This is terminal. We'll do the completion step
440+ // immediately after.
441+ return null ;
442+ }
443+
429444 function mountIndeterminateComponent ( current , workInProgress , priorityLevel ) {
430445 if ( current ) {
431446 throw new Error ( 'An indeterminate component should never have mounted.' ) ;
@@ -484,6 +499,7 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
484499 }
485500 }
486501 reconcileChildren ( current , workInProgress , value ) ;
502+ memoizeProps ( workInProgress , props ) ;
487503 return workInProgress . child ;
488504 }
489505 }
@@ -503,6 +519,7 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
503519 return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
504520 }
505521 reconcileChildren ( current , workInProgress , nextCoroutine . children ) ;
522+ memoizeProps ( workInProgress , nextCoroutine ) ;
506523 // This doesn't take arbitrary time so we could synchronously just begin
507524 // eagerly do the work of workInProgress.child as an optimization.
508525 return workInProgress . child ;
@@ -537,9 +554,11 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
537554 nextChildren ,
538555 priorityLevel
539556 ) ;
557+ memoizeProps ( workInProgress , nextChildren ) ;
540558 markChildAsProgressed ( current , workInProgress , priorityLevel ) ;
541559 } else {
542560 reconcileChildren ( current , workInProgress , nextChildren ) ;
561+ memoizeProps ( workInProgress , nextChildren ) ;
543562 }
544563 return workInProgress . child ;
545564 }
@@ -606,6 +625,18 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
606625 return null ;
607626 }
608627
628+ function memoizeProps ( workInProgress : Fiber , nextProps : any ) {
629+ workInProgress . memoizedProps = nextProps ;
630+ // Reset the pending props
631+ workInProgress . pendingProps = null ;
632+ }
633+
634+ function memoizeState ( workInProgress : Fiber , nextState : any ) {
635+ workInProgress . memoizedState = nextState ;
636+ // Don't reset the updateQueue, in case there are pending updates. Resetting
637+ // is handled by beginUpdateQueue.
638+ }
639+
609640 function beginWork ( current : ?Fiber , workInProgress : Fiber , priorityLevel : PriorityLevel ) : ?Fiber {
610641 if ( workInProgress . pendingWorkPriority === NoWork ||
611642 workInProgress . pendingWorkPriority > priorityLevel ) {
@@ -639,9 +670,7 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
639670 case HostComponent :
640671 return updateHostComponent ( current , workInProgress ) ;
641672 case HostText :
642- // Nothing to do here. This is terminal. We'll do the completion step
643- // immediately after.
644- return null ;
673+ return updateHostText ( current , workInProgress ) ;
645674 case CoroutineHandlerPhase :
646675 // This is a restart. Reset the tag to the initial phase.
647676 workInProgress . tag = CoroutineComponent ;
@@ -683,6 +712,14 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
683712 // Unmount the current children as if the component rendered null
684713 const nextChildren = null ;
685714 reconcileChildren ( current , workInProgress , nextChildren ) ;
715+
716+ if ( workInProgress . tag === ClassComponent ) {
717+ const instance = workInProgress . stateNode ;
718+ workInProgress . memoizedProps = instance . props ;
719+ workInProgress . memoizedState = instance . state ;
720+ workInProgress . pendingProps = null ;
721+ }
722+
686723 return workInProgress . child ;
687724 }
688725
0 commit comments