Skip to content

Commit 33e59ec

Browse files
committed
Double-render functions in strict mode
1 parent 10a7a5b commit 33e59ec

File tree

4 files changed

+52
-16
lines changed

4 files changed

+52
-16
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,20 @@ function updateForwardRef(
250250
ref,
251251
renderExpirationTime,
252252
);
253+
if (
254+
debugRenderPhaseSideEffects ||
255+
(debugRenderPhaseSideEffectsForStrictMode &&
256+
workInProgress.mode & StrictMode)
257+
) {
258+
renderWithHooks(
259+
current,
260+
workInProgress,
261+
render,
262+
nextProps,
263+
ref,
264+
renderExpirationTime,
265+
);
266+
}
253267
setCurrentPhase(null);
254268
} else {
255269
nextChildren = renderWithHooks(
@@ -543,6 +557,20 @@ function updateFunctionComponent(
543557
context,
544558
renderExpirationTime,
545559
);
560+
if (
561+
debugRenderPhaseSideEffects ||
562+
(debugRenderPhaseSideEffectsForStrictMode &&
563+
workInProgress.mode & StrictMode)
564+
) {
565+
renderWithHooks(
566+
current,
567+
workInProgress,
568+
Component,
569+
nextProps,
570+
context,
571+
renderExpirationTime,
572+
);
573+
}
546574
setCurrentPhase(null);
547575
} else {
548576
nextChildren = renderWithHooks(
@@ -1145,6 +1173,7 @@ function mountIndeterminateComponent(
11451173
context,
11461174
renderExpirationTime,
11471175
);
1176+
// TODO: double-render here in strict mode.
11481177
} else {
11491178
value = renderWithHooks(
11501179
null,

packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describe('ErrorBoundaryReconciliation', () => {
7070
if (isConcurrent) {
7171
renderer.unstable_flushAll();
7272
}
73-
}).toWarnDev(isConcurrent ? ['invalid', 'invalid'] : ['invalid']);
73+
}).toWarnDev(isConcurrent ? ['invalid', 'invalid', 'invalid', 'invalid'] : ['invalid']);
7474
const Fallback = fallbackTagName;
7575
expect(renderer).toMatchRenderedOutput(<Fallback prop="ErrorBoundary" />);
7676
}

packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,14 @@ describe('ReactTestRendererAsync', () => {
6666
expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']);
6767

6868
renderer.update(<Parent step={2} />);
69-
expect(renderer).toFlushAndYield(['A:2', 'B:2', 'C:2']);
69+
expect(renderer).toFlushAndYield(__DEV__ ? [
70+
'A:2',
71+
'A:2',
72+
'B:2',
73+
'B:2',
74+
'C:2',
75+
'C:2'
76+
] : ['A:2', 'B:2', 'C:2']);
7077
expect(renderer.toJSON()).toEqual(['A:2', 'B:2', 'C:2']);
7178
});
7279

packages/react/src/__tests__/forwardRef-test.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,11 @@ describe('forwardRef', () => {
241241

242242
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
243243
ReactNoop.flush();
244-
expect(renderCount).toBe(1);
244+
expect(renderCount).toBe(__DEV__ ? 2 : 1);
245245

246246
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
247247
ReactNoop.flush();
248-
expect(renderCount).toBe(2);
248+
expect(renderCount).toBe(__DEV__ ? 4 : 2);
249249
});
250250

251251
it('should bailout if forwardRef is wrapped in memo', () => {
@@ -264,28 +264,28 @@ describe('forwardRef', () => {
264264

265265
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
266266
ReactNoop.flush();
267-
expect(renderCount).toBe(1);
267+
expect(renderCount).toBe(__DEV__ ? 2 : 1);
268268

269269
expect(ref.current.type).toBe('div');
270270

271271
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
272272
ReactNoop.flush();
273-
expect(renderCount).toBe(1);
273+
expect(renderCount).toBe(__DEV__ ? 2 : 1);
274274

275275
const differentRef = React.createRef();
276276

277277
ReactNoop.render(
278278
<RefForwardingComponent ref={differentRef} optional="foo" />,
279279
);
280280
ReactNoop.flush();
281-
expect(renderCount).toBe(2);
281+
expect(renderCount).toBe(__DEV__ ? 4 : 2);
282282

283283
expect(ref.current).toBe(null);
284284
expect(differentRef.current.type).toBe('div');
285285

286286
ReactNoop.render(<RefForwardingComponent ref={ref} optional="bar" />);
287287
ReactNoop.flush();
288-
expect(renderCount).toBe(3);
288+
expect(renderCount).toBe(__DEV__ ? 6 : 3);
289289
});
290290

291291
it('should custom memo comparisons to compose', () => {
@@ -305,19 +305,19 @@ describe('forwardRef', () => {
305305

306306
ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="0" c="1" />);
307307
ReactNoop.flush();
308-
expect(renderCount).toBe(1);
308+
expect(renderCount).toBe(__DEV__ ? 2 : 1);
309309

310310
expect(ref.current.type).toBe('div');
311311

312312
// Changing either a or b rerenders
313313
ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="1" c="1" />);
314314
ReactNoop.flush();
315-
expect(renderCount).toBe(2);
315+
expect(renderCount).toBe(__DEV__ ? 4 : 2);
316316

317317
// Changing c doesn't rerender
318318
ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="1" c="2" />);
319319
ReactNoop.flush();
320-
expect(renderCount).toBe(2);
320+
expect(renderCount).toBe(__DEV__ ? 4 : 2);
321321

322322
const ComposedMemo = React.memo(
323323
RefForwardingComponent,
@@ -326,29 +326,29 @@ describe('forwardRef', () => {
326326

327327
ReactNoop.render(<ComposedMemo ref={ref} a="0" b="0" c="0" />);
328328
ReactNoop.flush();
329-
expect(renderCount).toBe(3);
329+
expect(renderCount).toBe(__DEV__ ? 6 : 3);
330330

331331
// Changing just b no longer updates
332332
ReactNoop.render(<ComposedMemo ref={ref} a="0" b="1" c="0" />);
333333
ReactNoop.flush();
334-
expect(renderCount).toBe(3);
334+
expect(renderCount).toBe(__DEV__ ? 6 : 3);
335335

336336
// Changing just a and c updates
337337
ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="2" />);
338338
ReactNoop.flush();
339-
expect(renderCount).toBe(4);
339+
expect(renderCount).toBe(__DEV__ ? 8 : 4);
340340

341341
// Changing just c does not update
342342
ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="3" />);
343343
ReactNoop.flush();
344-
expect(renderCount).toBe(4);
344+
expect(renderCount).toBe(__DEV__ ? 8 : 4);
345345

346346
// Changing ref still rerenders
347347
const differentRef = React.createRef();
348348

349349
ReactNoop.render(<ComposedMemo ref={differentRef} a="2" b="2" c="3" />);
350350
ReactNoop.flush();
351-
expect(renderCount).toBe(5);
351+
expect(renderCount).toBe(__DEV__ ? 10 : 5);
352352

353353
expect(ref.current).toBe(null);
354354
expect(differentRef.current.type).toBe('div');

0 commit comments

Comments
 (0)