Skip to content

Commit 8f45a7f

Browse files
authored
Warn about incorrect use of useImperativeHandle() (#14647)
1 parent 1fcbd22 commit 8f45a7f

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

packages/react-reconciler/src/ReactFiberHooks.js

+14
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,12 @@ export function useImperativeHandle<T>(
674674
): void {
675675
if (__DEV__) {
676676
currentHookNameInDev = 'useImperativeHandle';
677+
warning(
678+
typeof create === 'function',
679+
'Expected useImperativeHandle() second argument to be a function ' +
680+
'that creates a handle. Instead received: %s.',
681+
create !== null ? typeof create : 'null',
682+
);
677683
}
678684
// TODO: If deps are provided, should we skip comparing the ref itself?
679685
const nextDeps =
@@ -690,6 +696,14 @@ export function useImperativeHandle<T>(
690696
return () => refCallback(null);
691697
} else if (ref !== null && ref !== undefined) {
692698
const refObject = ref;
699+
if (__DEV__) {
700+
warning(
701+
refObject.hasOwnProperty('current'),
702+
'Expected useImperativeHandle() first argument to either be a ' +
703+
'ref callback or React.createRef() object. Instead received: %s.',
704+
'an object with keys {' + Object.keys(refObject).join(', ') + '}',
705+
);
706+
}
693707
const inst = create();
694708
refObject.current = inst;
695709
return () => {

packages/react-reconciler/src/ReactFiberScheduler.js

+13
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,9 @@ function commitAllLifeCycles(
489489
}
490490
}
491491
while (nextEffect !== null) {
492+
if (__DEV__) {
493+
setCurrentFiber(nextEffect);
494+
}
492495
const effectTag = nextEffect.effectTag;
493496

494497
if (effectTag & (Update | Callback)) {
@@ -513,6 +516,9 @@ function commitAllLifeCycles(
513516

514517
nextEffect = nextEffect.nextEffect;
515518
}
519+
if (__DEV__) {
520+
resetCurrentFiber();
521+
}
516522
}
517523

518524
function commitPassiveEffects(root: FiberRoot, firstEffect: Fiber): void {
@@ -526,6 +532,10 @@ function commitPassiveEffects(root: FiberRoot, firstEffect: Fiber): void {
526532

527533
let effect = firstEffect;
528534
do {
535+
if (__DEV__) {
536+
setCurrentFiber(effect);
537+
}
538+
529539
if (effect.effectTag & Passive) {
530540
let didError = false;
531541
let error;
@@ -549,6 +559,9 @@ function commitPassiveEffects(root: FiberRoot, firstEffect: Fiber): void {
549559
}
550560
effect = effect.nextEffect;
551561
} while (effect !== null);
562+
if (__DEV__) {
563+
resetCurrentFiber();
564+
}
552565

553566
isRendering = previousIsRendering;
554567

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

+39
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,45 @@ describe('ReactHooks', () => {
569569
]);
570570
});
571571

572+
it('warns for bad useImperativeHandle first arg', () => {
573+
const {useImperativeHandle} = React;
574+
function App() {
575+
useImperativeHandle({
576+
focus() {},
577+
});
578+
return null;
579+
}
580+
581+
expect(() => {
582+
expect(() => {
583+
ReactTestRenderer.create(<App />);
584+
}).toThrow('create is not a function');
585+
}).toWarnDev([
586+
'Expected useImperativeHandle() first argument to either be a ' +
587+
'ref callback or React.createRef() object. ' +
588+
'Instead received: an object with keys {focus}.',
589+
'Expected useImperativeHandle() second argument to be a function ' +
590+
'that creates a handle. Instead received: undefined.',
591+
]);
592+
});
593+
594+
it('warns for bad useImperativeHandle second arg', () => {
595+
const {useImperativeHandle} = React;
596+
const App = React.forwardRef((props, ref) => {
597+
useImperativeHandle(ref, {
598+
focus() {},
599+
});
600+
return null;
601+
});
602+
603+
expect(() => {
604+
ReactTestRenderer.create(<App />);
605+
}).toWarnDev([
606+
'Expected useImperativeHandle() second argument to be a function ' +
607+
'that creates a handle. Instead received: object.',
608+
]);
609+
});
610+
572611
// https://github.com/facebook/react/issues/14022
573612
it('works with ReactDOMServer calls inside a component', () => {
574613
const {useState} = React;

0 commit comments

Comments
 (0)