Skip to content

Commit 0fd195f

Browse files
update error message to include useLayoutEffect or useEffect on bad e… (#22279)
* update error message to include useLayoutEffect or useEffect on bad effect return * Update packages/react-reconciler/src/ReactFiberCommitWork.new.js Co-authored-by: Ricky <rickhanlonii@gmail.com> * use existing import Co-authored-by: Ricky <rickhanlonii@gmail.com>
1 parent cb8a506 commit 0fd195f

File tree

3 files changed

+35
-15
lines changed

3 files changed

+35
-15
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ function commitHookEffectListUnmount(
507507
}
508508
}
509509

510-
function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
510+
function commitHookEffectListMount(tag: HookFlags, finishedWork: Fiber) {
511511
const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
512512
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
513513
if (lastEffect !== null) {
@@ -522,17 +522,26 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
522522
if (__DEV__) {
523523
const destroy = effect.destroy;
524524
if (destroy !== undefined && typeof destroy !== 'function') {
525+
let hookName;
526+
if ((effect.tag & HookLayout) !== NoFlags) {
527+
hookName = 'useLayoutEffect';
528+
} else {
529+
hookName = 'useEffect';
530+
}
525531
let addendum;
526532
if (destroy === null) {
527533
addendum =
528534
' You returned null. If your effect does not require clean ' +
529535
'up, return undefined (or nothing).';
530536
} else if (typeof destroy.then === 'function') {
531537
addendum =
532-
'\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +
538+
'\n\nIt looks like you wrote ' +
539+
hookName +
540+
'(async () => ...) or returned a Promise. ' +
533541
'Instead, write the async function inside your effect ' +
534542
'and call it immediately:\n\n' +
535-
'useEffect(() => {\n' +
543+
hookName +
544+
'(() => {\n' +
536545
' async function fetchData() {\n' +
537546
' // You can await here\n' +
538547
' const response = await MyAPI.getData(someId);\n' +
@@ -545,8 +554,9 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
545554
addendum = ' You returned: ' + destroy;
546555
}
547556
console.error(
548-
'An effect function must not return anything besides a function, ' +
557+
'%s must not return anything besides a function, ' +
549558
'which is used for clean-up.%s',
559+
hookName,
550560
addendum,
551561
);
552562
}

packages/react-reconciler/src/ReactFiberCommitWork.old.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ function commitHookEffectListUnmount(
507507
}
508508
}
509509

510-
function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
510+
function commitHookEffectListMount(tag: HookFlags, finishedWork: Fiber) {
511511
const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
512512
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
513513
if (lastEffect !== null) {
@@ -522,17 +522,26 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
522522
if (__DEV__) {
523523
const destroy = effect.destroy;
524524
if (destroy !== undefined && typeof destroy !== 'function') {
525+
let hookName;
526+
if ((effect.tag & HookLayout) !== NoFlags) {
527+
hookName = 'useLayoutEffect';
528+
} else {
529+
hookName = 'useEffect';
530+
}
525531
let addendum;
526532
if (destroy === null) {
527533
addendum =
528534
' You returned null. If your effect does not require clean ' +
529535
'up, return undefined (or nothing).';
530536
} else if (typeof destroy.then === 'function') {
531537
addendum =
532-
'\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +
538+
'\n\nIt looks like you wrote ' +
539+
hookName +
540+
'(async () => ...) or returned a Promise. ' +
533541
'Instead, write the async function inside your effect ' +
534542
'and call it immediately:\n\n' +
535-
'useEffect(() => {\n' +
543+
hookName +
544+
'(() => {\n' +
536545
' async function fetchData() {\n' +
537546
' // You can await here\n' +
538547
' const response = await MyAPI.getData(someId);\n' +
@@ -545,8 +554,9 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
545554
addendum = ' You returned: ' + destroy;
546555
}
547556
console.error(
548-
'An effect function must not return anything besides a function, ' +
557+
'%s must not return anything besides a function, ' +
549558
'which is used for clean-up.%s',
559+
hookName,
550560
addendum,
551561
);
552562
}

packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,7 +2647,7 @@ describe('ReactHooksWithNoopRenderer', () => {
26472647
root1.render(<App return={17} />);
26482648
}),
26492649
).toErrorDev([
2650-
'Warning: An effect function must not return anything besides a ' +
2650+
'Warning: useEffect must not return anything besides a ' +
26512651
'function, which is used for clean-up. You returned: 17',
26522652
]);
26532653

@@ -2657,7 +2657,7 @@ describe('ReactHooksWithNoopRenderer', () => {
26572657
root2.render(<App return={null} />);
26582658
}),
26592659
).toErrorDev([
2660-
'Warning: An effect function must not return anything besides a ' +
2660+
'Warning: useEffect must not return anything besides a ' +
26612661
'function, which is used for clean-up. You returned null. If your ' +
26622662
'effect does not require clean up, return undefined (or nothing).',
26632663
]);
@@ -2668,7 +2668,7 @@ describe('ReactHooksWithNoopRenderer', () => {
26682668
root3.render(<App return={Promise.resolve()} />);
26692669
}),
26702670
).toErrorDev([
2671-
'Warning: An effect function must not return anything besides a ' +
2671+
'Warning: useEffect must not return anything besides a ' +
26722672
'function, which is used for clean-up.\n\n' +
26732673
'It looks like you wrote useEffect(async () => ...) or returned a Promise.',
26742674
]);
@@ -2873,7 +2873,7 @@ describe('ReactHooksWithNoopRenderer', () => {
28732873
root1.render(<App return={17} />);
28742874
}),
28752875
).toErrorDev([
2876-
'Warning: An effect function must not return anything besides a ' +
2876+
'Warning: useLayoutEffect must not return anything besides a ' +
28772877
'function, which is used for clean-up. You returned: 17',
28782878
]);
28792879

@@ -2883,7 +2883,7 @@ describe('ReactHooksWithNoopRenderer', () => {
28832883
root2.render(<App return={null} />);
28842884
}),
28852885
).toErrorDev([
2886-
'Warning: An effect function must not return anything besides a ' +
2886+
'Warning: useLayoutEffect must not return anything besides a ' +
28872887
'function, which is used for clean-up. You returned null. If your ' +
28882888
'effect does not require clean up, return undefined (or nothing).',
28892889
]);
@@ -2894,9 +2894,9 @@ describe('ReactHooksWithNoopRenderer', () => {
28942894
root3.render(<App return={Promise.resolve()} />);
28952895
}),
28962896
).toErrorDev([
2897-
'Warning: An effect function must not return anything besides a ' +
2897+
'Warning: useLayoutEffect must not return anything besides a ' +
28982898
'function, which is used for clean-up.\n\n' +
2899-
'It looks like you wrote useEffect(async () => ...) or returned a Promise.',
2899+
'It looks like you wrote useLayoutEffect(async () => ...) or returned a Promise.',
29002900
]);
29012901

29022902
// Error on unmount because React assumes the value is a function

0 commit comments

Comments
 (0)