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:
Sophie Alpert
2018-11-02 14:43:45 -07:00
committed by GitHub
parent ae196e84b6
commit 293fed8993
2 changed files with 48 additions and 2 deletions
+20 -2
View File
@@ -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 **)',
]);
});
});