Skip to content

Commit 51c0791

Browse files
authored
Warn when second argument is passed to useCallback (#14729)
1 parent 70d4075 commit 51c0791

3 files changed

Lines changed: 246 additions & 124 deletions

File tree

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js‎

Lines changed: 110 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -613,8 +613,114 @@ describe('ReactDOMServerHooks', () => {
613613
});
614614

615615
describe('useContext',()=>{
616+
itThrowsWhenRendering(
617+
'if used inside a class component',
618+
asyncrender=>{
619+
constContext=React.createContext({},()=>{});
620+
classCounterextendsReact.Component{
621+
render(){
622+
let[count]=useContext(Context);
623+
return<Texttext={count}/>;
624+
}
625+
}
626+
627+
returnrender(<Counter/>);
628+
},
629+
'Hooks can only be called inside the body of a function component.',
630+
);
631+
});
632+
633+
itRenders(
634+
'can use the same context multiple times in the same function',
635+
asyncrender=>{
636+
constContext=React.createContext({foo: 0,bar: 0,baz: 0});
637+
638+
functionProvider(props){
639+
return(
640+
<Context.Provider
641+
value={{foo: props.foo,bar: props.bar,baz: props.baz}}>
642+
{props.children}
643+
</Context.Provider>
644+
);
645+
}
646+
647+
functionFooAndBar(){
648+
const{foo}=useContext(Context);
649+
const{bar}=useContext(Context);
650+
return<Texttext={`Foo: ${foo}, Bar: ${bar}`}/>;
651+
}
652+
653+
functionBaz(){
654+
const{baz}=useContext(Context);
655+
return<Texttext={'Baz: '+baz}/>;
656+
}
657+
658+
classIndirectionextendsReact.Component{
659+
render(){
660+
returnthis.props.children;
661+
}
662+
}
663+
664+
functionApp(props){
665+
return(
666+
<div>
667+
<Providerfoo={props.foo}bar={props.bar}baz={props.baz}>
668+
<Indirection>
669+
<Indirection>
670+
<FooAndBar/>
671+
</Indirection>
672+
<Indirection>
673+
<Baz/>
674+
</Indirection>
675+
</Indirection>
676+
</Provider>
677+
</div>
678+
);
679+
}
680+
681+
constdomNode=awaitrender(<Appfoo={1}bar={3}baz={5}/>);
682+
expect(clearYields()).toEqual(['Foo: 1, Bar: 3','Baz: 5']);
683+
expect(domNode.childNodes.length).toBe(2);
684+
expect(domNode.firstChild.tagName).toEqual('SPAN');
685+
expect(domNode.firstChild.textContent).toEqual('Foo: 1, Bar: 3');
686+
expect(domNode.lastChild.tagName).toEqual('SPAN');
687+
expect(domNode.lastChild.textContent).toEqual('Baz: 5');
688+
},
689+
);
690+
691+
itRenders('warns when bitmask is passed to useContext',asyncrender=>{
692+
letContext=React.createContext('Hi');
693+
694+
functionFoo(){
695+
return<span>{useContext(Context,1)}</span>;
696+
}
697+
698+
constdomNode=awaitrender(<Foo/>,1);
699+
expect(domNode.textContent).toBe('Hi');
700+
});
701+
702+
describe('useDebugValue',()=>{
703+
itRenders('is a noop',asyncrender=>{
704+
functionCounter(props){
705+
constdebugValue=useDebugValue(123);
706+
return<Texttext={typeofdebugValue}/>;
707+
}
708+
709+
constdomNode=awaitrender(<Counter/>);
710+
expect(domNode.textContent).toEqual('undefined');
711+
});
712+
});
713+
714+
describe('readContext',()=>{
715+
functionreadContext(Context,observedBits){
716+
constdispatcher=
717+
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
718+
.ReactCurrentDispatcher.current;
719+
returndispatcher.readContext(Context,observedBits);
720+
}
721+
616722
itRenders(
617-
'can use the same context multiple times in the same function',
723+
'can read the same context multiple times in the same function',
618724
asyncrender=>{
619725
constContext=React.createContext(
620726
{foo: 0,bar: 0,baz: 0},
@@ -643,13 +749,13 @@ describe('ReactDOMServerHooks', () => {
643749
}
644750

645751
functionFooAndBar(){
646-
const{foo}=useContext(Context,0b001);
647-
const{bar}=useContext(Context,0b010);
752+
const{foo}=readContext(Context,0b001);
753+
const{bar}=readContext(Context,0b010);
648754
return<Texttext={`Foo: ${foo}, Bar: ${bar}`}/>;
649755
}
650756

651757
functionBaz(){
652-
const{baz}=useContext(Context,0b100);
758+
const{baz}=readContext(Context,0b100);
653759
return<Texttext={'Baz: '+baz}/>;
654760
}
655761

@@ -689,43 +795,6 @@ describe('ReactDOMServerHooks', () => {
689795
},
690796
);
691797

692-
itThrowsWhenRendering(
693-
'if used inside a class component',
694-
asyncrender=>{
695-
constContext=React.createContext({},()=>{});
696-
classCounterextendsReact.Component{
697-
render(){
698-
let[count]=useContext(Context);
699-
return<Texttext={count}/>;
700-
}
701-
}
702-
703-
returnrender(<Counter/>);
704-
},
705-
'Hooks can only be called inside the body of a function component.',
706-
);
707-
});
708-
709-
describe('useDebugValue',()=>{
710-
itRenders('is a noop',asyncrender=>{
711-
functionCounter(props){
712-
constdebugValue=useDebugValue(123);
713-
return<Texttext={typeofdebugValue}/>;
714-
}
715-
716-
constdomNode=awaitrender(<Counter/>);
717-
expect(domNode.textContent).toEqual('undefined');
718-
});
719-
});
720-
721-
describe('readContext',()=>{
722-
functionreadContext(Context,observedBits){
723-
constdispatcher=
724-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
725-
.ReactCurrentDispatcher.current;
726-
returndispatcher.readContext(Context,observedBits);
727-
}
728-
729798
itRenders('with a warning inside useMemo and useReducer',asyncrender=>{
730799
constContext=React.createContext(42);
731800

0 commit comments

Comments
 (0)