Skip to content

Commit 8f45a7f

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

3 files changed

Lines changed: 66 additions & 0 deletions

File tree

‎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+
typeofcreate==='function',
679+
'Expected useImperativeHandle() second argument to be a function '+
680+
'that creates a handle. Instead received: %s.',
681+
create!==null ? typeofcreate : '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
}elseif(ref!==null&&ref!==undefined){
692698
constrefObject=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
constinst=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
consteffectTag=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
functioncommitPassiveEffects(root: FiberRoot,firstEffect: Fiber): void{
@@ -526,6 +532,10 @@ function commitPassiveEffects(root: FiberRoot, firstEffect: Fiber): void {
526532

527533
leteffect=firstEffect;
528534
do{
535+
if(__DEV__){
536+
setCurrentFiber(effect);
537+
}
538+
529539
if(effect.effectTag&Passive){
530540
letdidError=false;
531541
leterror;
@@ -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: 39 additions & 0 deletions
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+
functionApp(){
575+
useImperativeHandle({
576+
focus(){},
577+
});
578+
returnnull;
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+
constApp=React.forwardRef((props,ref)=>{
597+
useImperativeHandle(ref,{
598+
focus(){},
599+
});
600+
returnnull;
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)