Skip to content

Commit ca8c97a

Browse files
committed
Warn about incorrect use of useImperativeHandle()
1 parent b5a3df6 commit ca8c97a

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

packages/react-reconciler/src/ReactFiberHooks.js

Lines changed: 14 additions & 0 deletions
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

Lines changed: 13 additions & 0 deletions
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(nextEffect);
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(nextEffect);
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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,47 @@ 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+
let root;
581+
582+
expect(() => {
583+
expect(() => {
584+
root = ReactTestRenderer.create(<App />);
585+
}).toThrow('create is not a function');
586+
}).toWarnDev([
587+
'Expected useImperativeHandle() first argument to either be a ' +
588+
'ref callback or React.createRef() object. ' +
589+
'Instead received: an object with keys {focus}.',
590+
'Expected useImperativeHandle() second argument to be a function ' +
591+
'that creates a handle. Instead received: undefined.',
592+
]);
593+
});
594+
595+
it('warns for bad useImperativeHandle second arg', () => {
596+
const {useImperativeHandle} = React;
597+
const App = React.forwardRef((props, ref) => {
598+
useImperativeHandle(ref, {
599+
focus() {},
600+
});
601+
return null;
602+
});
603+
let root;
604+
605+
expect(() => {
606+
root = ReactTestRenderer.create(<App />);
607+
}).toWarnDev([
608+
'Expected useImperativeHandle() second argument to be a function ' +
609+
'that creates a handle. Instead received: object.',
610+
]);
611+
});
612+
572613
// https://github.com/facebook/react/issues/14022
573614
it('works with ReactDOMServer calls inside a component', () => {
574615
const {useState} = React;

0 commit comments

Comments
 (0)