mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Warn for bad useEffect return value (#14069)
Mostly to catch this:
```js
useEffect(async () => {
// ...
return cleanup;
});
```
Is this too restrictive? Not sure if you would want to do like
```js
useEffect(() => ref.current.style.color = 'red');
```
which would give a false positive here. We can always relax it to only warn on Promises if people complain.
This commit is contained in:
+20
-2
@@ -295,8 +295,26 @@ function commitHookEffectList(
|
||||
if ((effect.tag & mountTag) !== NoHookEffect) {
|
||||
// Mount
|
||||
const create = effect.create;
|
||||
const destroy = create();
|
||||
effect.destroy = typeof destroy === 'function' ? destroy : null;
|
||||
let destroy = create();
|
||||
if (typeof destroy !== 'function') {
|
||||
if (__DEV__) {
|
||||
if (destroy !== null && destroy !== undefined) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'useEffect function must return a cleanup function or ' +
|
||||
'nothing.%s%s',
|
||||
typeof destroy.then === 'function'
|
||||
? ' Promises and useEffect(async () => ...) are not ' +
|
||||
'supported, but you can call an async function inside an ' +
|
||||
'effect.'
|
||||
: '',
|
||||
getStackByFiberInDevAndProd(finishedWork),
|
||||
);
|
||||
}
|
||||
}
|
||||
destroy = null;
|
||||
}
|
||||
effect.destroy = destroy;
|
||||
}
|
||||
effect = effect.next;
|
||||
} while (effect !== firstEffect);
|
||||
|
||||
@@ -51,4 +51,32 @@ describe('ReactHooks', () => {
|
||||
]);
|
||||
expect(ReactTestRenderer).toHaveYielded(['Did commit: A, B']);
|
||||
});
|
||||
|
||||
it('warns for bad useEffect return values', () => {
|
||||
const {useLayoutEffect} = React;
|
||||
function App(props) {
|
||||
useLayoutEffect(() => {
|
||||
return props.return;
|
||||
});
|
||||
return null;
|
||||
}
|
||||
let root;
|
||||
|
||||
expect(() => {
|
||||
root = ReactTestRenderer.create(<App return={17} />);
|
||||
}).toWarnDev([
|
||||
'Warning: useEffect function must return a cleanup function or ' +
|
||||
'nothing.\n' +
|
||||
' in App (at **)',
|
||||
]);
|
||||
|
||||
expect(() => {
|
||||
root.update(<App return={Promise.resolve()} />);
|
||||
}).toWarnDev([
|
||||
'Warning: useEffect function must return a cleanup function or ' +
|
||||
'nothing. Promises and useEffect(async () => ...) are not supported, ' +
|
||||
'but you can call an async function inside an effect.\n' +
|
||||
' in App (at **)',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user