forceUpdate
Adds a field to the update queue that causes shouldComponentUpdate to be skipped.
Andrew Clark committed
Aug 4, 2016 at 19:16 UTC
f514662ca0959fd42031396c5c21dc3241abbf66
3 files changed
+50
-1
src/renderers/shared/fiber/ReactFiberBeginWork.js
+8
-1
@@ -163,6 +163,12 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>, getSchedu
163
updateQueue.isReplace = true;
164
scheduleUpdate(fiber, updateQueue, LowPriority);
165
},
166
+ enqueueForceUpdate(instance) {
167
+ const fiber = ReactInstanceMap.get(instance);
168
+ const updateQueue = fiber.updateQueue || createUpdateQueue(null);
169
+ updateQueue.isForced = true;
170
+ scheduleUpdate(fiber, updateQueue, LowPriority);
171
+ },
172
enqueueCallback(instance, callback) {
173
const fiber = ReactInstanceMap.get(instance);
174
let updateQueue = fiber.updateQueue ?
@@ -204,7 +210,8 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>, getSchedu
210
// The instance needs access to the fiber so that it can schedule updates
211
ReactInstanceMap.set(instance, workInProgress);
212
instance.updater = updater;
207
- } else if (typeof instance.shouldComponentUpdate === 'function') {
213
+ } else if (typeof instance.shouldComponentUpdate === 'function' &&
214
+ !(updateQueue && updateQueue.isForced)) {
215
if (workInProgress.memoizedProps !== null) {
216
// Reset the props, in case this is a ping-pong case rather than a
217
// completed update case. For the completed update case, the instance
src/renderers/shared/fiber/ReactFiberUpdateQueue.js
+2
@@ -21,6 +21,7 @@ type UpdateQueueNode = {
21
22
export type UpdateQueue = UpdateQueueNode & {
23
isReplace: boolean,
24
+ isForced: boolean,
25
tail: UpdateQueueNode
26
};
27
@@ -31,6 +32,7 @@ exports.createUpdateQueue = function(partialState : mixed) : UpdateQueue {
32
callbackWasCalled: false,
33
next: null,
34
isReplace: false,
35
+ isForced: false,
36
tail: (null : any),
37
};
38
queue.tail = queue;
src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
+40
@@ -682,4 +682,44 @@ describe('ReactIncremental', () => {
682
ReactNoop.flush();
683
expect(instance.state).toEqual({ d: 'd' });
684
});
685
+
686
+ it('can forceUpdate', () => {
687
+ const ops = [];
688
+
689
+ function Baz() {
690
+ ops.push('Baz');
691
+ return <div />;
692
+ }
693
+
694
+ let instance;
695
+ class Bar extends React.Component {
696
+ constructor() {
697
+ super();
698
+ instance = this;
699
+ }
700
+ shouldComponentUpdate() {
701
+ return false;
702
+ }
703
+ render() {
704
+ ops.push('Bar');
705
+ return <Baz />;
706
+ }
707
+ }
708
+
709
+ function Foo() {
710
+ ops.push('Foo');
711
+ return (
712
+ <div>
713
+ <Bar />
714
+ </div>
715
+ );
716
+ }
717
+
718
+ ReactNoop.render(<Foo />);
719
+ ReactNoop.flush();
720
+ expect(ops).toEqual(['Foo', 'Bar', 'Baz']);
721
+ instance.forceUpdate();
722
+ ReactNoop.flush();
723
+ expect(ops).toEqual(['Foo', 'Bar', 'Baz', 'Bar', 'Baz']);
724
+ });
725
});