Skip to content

Commit 166d236

Browse files
committed
Added invariant with component stack (in dev) for useRef without function
1 parent 60efe32 commit 166d236

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,14 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
168168
}
169169

170170
function updateUseRef(current, workInProgress) {
171-
const nextChildren = workInProgress.type.renderProp(
171+
const renderProp = workInProgress.type.renderProp;
172+
invariant(
173+
typeof renderProp === 'function',
174+
'useRef requires a render function but was given %s.%s',
175+
renderProp === null ? 'null' : typeof renderProp,
176+
ReactDebugCurrentFiber.getCurrentFiberStackAddendum() || '',
177+
);
178+
const nextChildren = renderProp(
172179
workInProgress.pendingProps,
173180
workInProgress.ref,
174181
);

packages/react/src/__tests__/useRef-test.internal.js

+30-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ describe('useRef', () => {
1414
let ReactFeatureFlags;
1515
let ReactNoop;
1616

17+
function normalizeCodeLocInfo(str) {
18+
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
19+
}
20+
1721
beforeEach(() => {
1822
jest.resetModules();
1923
ReactFeatureFlags = require('shared/ReactFeatureFlags');
@@ -159,7 +163,7 @@ describe('useRef', () => {
159163
expect(ref.value).toBe(null);
160164
});
161165

162-
it('should error if not provided a callback', () => {
166+
it('should warn if not provided a callback during creation', () => {
163167
expect(() => React.useRef(undefined)).toWarnDev(
164168
'useRef requires a render function but was given undefined.',
165169
);
@@ -170,4 +174,29 @@ describe('useRef', () => {
170174
'useRef requires a render function but was given string.',
171175
);
172176
});
177+
178+
it('should error with a callstack if rendered without a function', () => {
179+
let RefForwardingComponent;
180+
expect(() => {
181+
RefForwardingComponent = React.useRef();
182+
}).toWarnDev('useRef requires a render function but was given undefined.');
183+
184+
ReactNoop.render(
185+
<div>
186+
<RefForwardingComponent />
187+
</div>,
188+
);
189+
190+
let caughtError;
191+
try {
192+
ReactNoop.flush();
193+
} catch (error) {
194+
caughtError = error;
195+
}
196+
expect(caughtError).toBeDefined();
197+
expect(normalizeCodeLocInfo(caughtError.message)).toBe(
198+
'useRef requires a render function but was given undefined.' +
199+
(__DEV__ ? '\n in div (at **)' : ''),
200+
);
201+
});
173202
});

0 commit comments

Comments
 (0)