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
};