@samitouri / QOS-React / commits / 17ab69c1ec

[Fiber] Fix to call deferred callbackQueue even if updates are aborted (#9634)

* Fix to call deferred callbackQueue even if updates are aborted * Add an assertion to make sure the update processed, but wasn't committed yet

Toru Kobayashi committed May 13, 2017 at 02:45 UTC 17ab69c1ec9e2d994bb58955214c463df3b377cb
3 files changed +57 -1
scripts/fiber/tests-passing.txt
+1
@@ -1673,6 +1673,7 @@ src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
1673 * should render a simple component, in steps if needed
1674 * updates a previous render
1675 * can cancel partially rendered work and restart
1676 +* should call callbacks even if updates are aborted
1677 * can deprioritize unfinished work and resume it later
1678 * can deprioritize a tree from without dropping work
1679 * can resume work in a subtree even when a parent bails out
src/renderers/shared/fiber/ReactFiberUpdateQueue.js
+1 -1
@@ -426,7 +426,7 @@ function beginUpdateQueue(
426 // a new state object.
427 let state = prevState;
428 let dontMutatePrevState = true;
429 - let callbackList = null;
429 + let callbackList = queue.callbackList;
430 let update = queue.first;
431 while (
432 update !== null &&
src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
+55
@@ -183,6 +183,61 @@ describe('ReactIncremental', () => {
183 expect(ops).toEqual(['Foo', 'Bar', 'Bar']);
184 });
185
186 + it('should call callbacks even if updates are aborted', () => {
187 + const ops = [];
188 + let inst;
189 +
190 + class Foo extends React.Component {
191 + constructor(props) {
192 + super(props);
193 + this.state = {
194 + text: 'foo',
195 + text2: 'foo',
196 + };
197 + inst = this;
198 + }
199 + render() {
200 + return (
201 + <div>
202 + <div>{this.state.text}</div>
203 + <div>{this.state.text2}</div>
204 + </div>
205 + );
206 + }
207 + }
208 +
209 + ReactNoop.render(<Foo />);
210 + ReactNoop.flush();
211 +
212 + inst.setState(
213 + () => {
214 + ops.push('setState1');
215 + return {text: 'bar'};
216 + },
217 + () => ops.push('callback1'),
218 + );
219 +
220 + // Flush part of the work
221 + ReactNoop.flushDeferredPri(20 + 5);
222 +
223 + expect(ops).toEqual(['setState1']);
224 +
225 + // This will abort the previous work and restart
226 + inst.setState(
227 + () => {
228 + ops.push('setState2');
229 + return {text2: 'baz'};
230 + },
231 + () => ops.push('callback2'),
232 + );
233 +
234 + // Flush the rest of the work which now includes the low priority
235 + ReactNoop.flush();
236 +
237 + expect(ops).toEqual(['setState1', 'setState2', 'callback1', 'callback2']);
238 + expect(inst.state).toEqual({text: 'bar', text2: 'baz'});
239 + });
240 +
241 it('can deprioritize unfinished work and resume it later', () => {
242 var ops = [];
243