@samitouri / QOS-React / commits / 2517a11875

Update refs even if shouldComponentUpdate returns false

Implemented using a Ref effect type.

Andrew Clark committed Jan 4, 2017 at 12:05 UTC 2517a11875336ce9589087ba8385c577238ee1f8
6 files changed +46 -22
scripts/fiber/tests-failing.txt
-3
@@ -59,9 +59,6 @@ src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js
59 src/renderers/shared/shared/__tests__/ReactComponentLifeCycle-test.js
60 * should carry through each of the phases of setup
61
62 -src/renderers/shared/shared/__tests__/ReactCompositeComponent-test.js
63 -* should update refs if shouldComponentUpdate gives false
64 -
62 src/renderers/shared/shared/__tests__/ReactEmptyComponent-test.js
63 * should still throw when rendering to undefined
64
scripts/fiber/tests-passing.txt
+1
@@ -1380,6 +1380,7 @@ src/renderers/shared/shared/__tests__/ReactCompositeComponent-test.js
1380 * should trigger componentWillReceiveProps for context changes
1381 * only renders once if updated in componentWillReceiveProps
1382 * only renders once if updated in componentWillReceiveProps when batching
1383 +* should update refs if shouldComponentUpdate gives false
1384 * should allow access to findDOMNode in componentWillUnmount
1385 * context should be passed down from the parent
1386 * should replace state
src/renderers/shared/fiber/ReactFiberBeginWork.js
+16
@@ -58,6 +58,7 @@ var {
58 Placement,
59 ContentReset,
60 Err,
61 + Ref,
62 } = require('ReactTypeOfSideEffect');
63 var ReactCurrentOwner = require('ReactCurrentOwner');
64 var ReactFiberClassComponent = require('ReactFiberClassComponent');
@@ -180,6 +181,14 @@ module.exports = function<T, P, I, TI, C, CX, CI>(
181 return workInProgress.child;
182 }
183
184 + function markRef(current : ?Fiber, workInProgress : Fiber) {
185 + const ref = workInProgress.ref;
186 + if (ref && (!current || current.ref !== ref)) {
187 + // Schedule a Ref effect
188 + workInProgress.effectTag |= Ref;
189 + }
190 + }
191 +
192 function updateFunctionalComponent(current, workInProgress) {
193 var fn = workInProgress.type;
194 var nextProps = workInProgress.pendingProps;
@@ -245,6 +254,10 @@ module.exports = function<T, P, I, TI, C, CX, CI>(
254 hasContext : boolean,
255 ) {
256 // Schedule side-effects
257 +
258 + // Refs should update even if shouldComponentUpdate returns false
259 + markRef(current, workInProgress);
260 +
261 if (shouldUpdate) {
262 workInProgress.effectTag |= Update;
263 } else {
@@ -364,6 +377,9 @@ module.exports = function<T, P, I, TI, C, CX, CI>(
377 // empty, we need to schedule the text content to be reset.
378 workInProgress.effectTag |= ContentReset;
379 }
380 +
381 + markRef(current, workInProgress);
382 +
383 if (nextProps.hidden &&
384 workInProgress.pendingWorkPriority !== OffscreenPriority) {
385 // If this host component is hidden, we can bail out on the children.
src/renderers/shared/fiber/ReactFiberCommitWork.js
+12 -9
@@ -84,13 +84,6 @@ module.exports = function<T, P, I, TI, C, CX, CI>(
84 }
85 }
86
87 - function attachRef(current : ?Fiber, finishedWork : Fiber, instance : any) {
88 - const ref = finishedWork.ref;
89 - if (ref && (!current || current.ref !== ref)) {
90 - ref(instance);
91 - }
92 - }
93 -
87 function getHostParent(fiber : Fiber) : I | C {
88 let parent = fiber.return;
89 while (parent) {
@@ -416,7 +409,6 @@ module.exports = function<T, P, I, TI, C, CX, CI>(
409 instance.componentDidUpdate(prevProps, prevState);
410 }
411 }
419 - attachRef(current, finishedWork, instance);
412 }
413 const callbackList = finishedWork.callbackList;
414 if (callbackList) {
@@ -434,7 +426,6 @@ module.exports = function<T, P, I, TI, C, CX, CI>(
426 }
427 case HostComponent: {
428 const instance : I = finishedWork.stateNode;
437 - attachRef(current, finishedWork, instance);
429
430 // Renderers may schedule work to be done after host components are mounted
431 // (eg DOM renderer may schedule auto-focus for inputs and form controls).
@@ -465,11 +456,23 @@ module.exports = function<T, P, I, TI, C, CX, CI>(
456 }
457 }
458
459 + function commitRef(finishedWork : Fiber) {
460 + if (finishedWork.tag !== ClassComponent && finishedWork.tag !== HostComponent) {
461 + return;
462 + }
463 + const ref = finishedWork.ref;
464 + if (ref) {
465 + const instance = finishedWork.stateNode;
466 + ref(instance);
467 + }
468 + }
469 +
470 return {
471 commitPlacement,
472 commitDeletion,
473 commitWork,
474 commitLifeCycles,
475 + commitRef,
476 };
477
478 };
src/renderers/shared/fiber/ReactFiberScheduler.js
+7 -1
@@ -49,6 +49,7 @@ var {
49 ContentReset,
50 Callback,
51 Err,
52 + Ref,
53 } = require('ReactTypeOfSideEffect');
54
55 var {
@@ -88,6 +89,7 @@ module.exports = function<T, P, I, TI, C, CX, CI>(config : HostConfig<T, P, I, T
89 commitDeletion,
90 commitWork,
91 commitLifeCycles,
92 + commitRef,
93 } = ReactFiberCommitWork(config, hostContext, captureError);
94 const {
95 scheduleAnimationCallback: hostScheduleAnimationCallback,
@@ -241,7 +243,7 @@ module.exports = function<T, P, I, TI, C, CX, CI>(config : HostConfig<T, P, I, T
243 // possible bitmap value, we remove the secondary effects from the
244 // effect tag and switch on that value.
245 let primaryEffectTag =
244 - nextEffect.effectTag & ~(Callback | Err | ContentReset);
246 + nextEffect.effectTag & ~(Callback | Err | ContentReset | Ref);
247 switch (primaryEffectTag) {
248 case Placement: {
249 commitPlacement(nextEffect);
@@ -293,6 +295,10 @@ module.exports = function<T, P, I, TI, C, CX, CI>(config : HostConfig<T, P, I, T
295 commitLifeCycles(current, nextEffect);
296 }
297
298 + if (nextEffect.effectTag & Ref) {
299 + commitRef(nextEffect);
300 + }
301 +
302 if (nextEffect.effectTag & Err) {
303 commitErrorHandling(nextEffect);
304 }
src/renderers/shared/fiber/ReactTypeOfSideEffect.js
+10 -9
@@ -12,15 +12,16 @@
12
13 'use strict';
14
15 -export type TypeOfSideEffect = 0 | 1 | 2 | 3 | 4 | 8 | 16 | 32;
15 +export type TypeOfSideEffect = 0 | 1 | 2 | 3 | 4 | 8 | 16 | 32 | 64;
16
17 module.exports = {
18 - NoEffect: 0, // 0b000000
19 - Placement: 1, // 0b000001
20 - Update: 2, // 0b000010
21 - PlacementAndUpdate: 3, // 0b000011
22 - Deletion: 4, // 0b000100
23 - ContentReset: 8, // 0b001000
24 - Callback: 16, // 0b010000
25 - Err: 32, // 0b100000
18 + NoEffect: 0, // 0b0000000
19 + Placement: 1, // 0b0000001
20 + Update: 2, // 0b0000010
21 + PlacementAndUpdate: 3, // 0b0000011
22 + Deletion: 4, // 0b0000100
23 + ContentReset: 8, // 0b0001000
24 + Callback: 16, // 0b0010000
25 + Err: 32, // 0b0100000
26 + Ref: 64, // 0b1000000
27 };