Skip to content

Commit

Permalink
Warn when second argument is passed to useCallback (#14729)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon authored Jan 31, 2019
1 parent 70d4075 commit 51c0791
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -613,8 +613,114 @@ describe('ReactDOMServerHooks', () => {
});

describe('useContext', () => {
itThrowsWhenRendering(
'if used inside a class component',
async render => {
const Context = React.createContext({}, () => {});
class Counter extends React.Component {
render() {
let [count] = useContext(Context);
return <Text text={count} />;
}
}

return render(<Counter />);
},
'Hooks can only be called inside the body of a function component.',
);
});

itRenders(
'can use the same context multiple times in the same function',
async render => {
const Context = React.createContext({foo: 0, bar: 0, baz: 0});

function Provider(props) {
return (
<Context.Provider
value={{foo: props.foo, bar: props.bar, baz: props.baz}}>
{props.children}
</Context.Provider>
);
}

function FooAndBar() {
const {foo} = useContext(Context);
const {bar} = useContext(Context);
return <Text text={`Foo: ${foo}, Bar: ${bar}`} />;
}

function Baz() {
const {baz} = useContext(Context);
return <Text text={'Baz: ' + baz} />;
}

class Indirection extends React.Component {
render() {
return this.props.children;
}
}

function App(props) {
return (
<div>
<Provider foo={props.foo} bar={props.bar} baz={props.baz}>
<Indirection>
<Indirection>
<FooAndBar />
</Indirection>
<Indirection>
<Baz />
</Indirection>
</Indirection>
</Provider>
</div>
);
}

const domNode = await render(<App foo={1} bar={3} baz={5} />);
expect(clearYields()).toEqual(['Foo: 1, Bar: 3', 'Baz: 5']);
expect(domNode.childNodes.length).toBe(2);
expect(domNode.firstChild.tagName).toEqual('SPAN');
expect(domNode.firstChild.textContent).toEqual('Foo: 1, Bar: 3');
expect(domNode.lastChild.tagName).toEqual('SPAN');
expect(domNode.lastChild.textContent).toEqual('Baz: 5');
},
);

itRenders('warns when bitmask is passed to useContext', async render => {
let Context = React.createContext('Hi');

function Foo() {
return <span>{useContext(Context, 1)}</span>;
}

const domNode = await render(<Foo />, 1);
expect(domNode.textContent).toBe('Hi');
});

describe('useDebugValue', () => {
itRenders('is a noop', async render => {
function Counter(props) {
const debugValue = useDebugValue(123);
return <Text text={typeof debugValue} />;
}

const domNode = await render(<Counter />);
expect(domNode.textContent).toEqual('undefined');
});
});

describe('readContext', () => {
function readContext(Context, observedBits) {
const dispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher.current;
return dispatcher.readContext(Context, observedBits);
}

itRenders(
'can use the same context multiple times in the same function',
'can read the same context multiple times in the same function',
async render => {
const Context = React.createContext(
{foo: 0, bar: 0, baz: 0},
Expand Down Expand Up @@ -643,13 +749,13 @@ describe('ReactDOMServerHooks', () => {
}

function FooAndBar() {
const {foo} = useContext(Context, 0b001);
const {bar} = useContext(Context, 0b010);
const {foo} = readContext(Context, 0b001);
const {bar} = readContext(Context, 0b010);
return <Text text={`Foo: ${foo}, Bar: ${bar}`} />;
}

function Baz() {
const {baz} = useContext(Context, 0b100);
const {baz} = readContext(Context, 0b100);
return <Text text={'Baz: ' + baz} />;
}

Expand Down Expand Up @@ -689,43 +795,6 @@ describe('ReactDOMServerHooks', () => {
},
);

itThrowsWhenRendering(
'if used inside a class component',
async render => {
const Context = React.createContext({}, () => {});
class Counter extends React.Component {
render() {
let [count] = useContext(Context);
return <Text text={count} />;
}
}

return render(<Counter />);
},
'Hooks can only be called inside the body of a function component.',
);
});

describe('useDebugValue', () => {
itRenders('is a noop', async render => {
function Counter(props) {
const debugValue = useDebugValue(123);
return <Text text={typeof debugValue} />;
}

const domNode = await render(<Counter />);
expect(domNode.textContent).toEqual('undefined');
});
});

describe('readContext', () => {
function readContext(Context, observedBits) {
const dispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher.current;
return dispatcher.readContext(Context, observedBits);
}

itRenders('with a warning inside useMemo and useReducer', async render => {
const Context = React.createContext(42);

Expand Down
Loading

0 comments on commit 51c0791

Please sign in to comment.