This warning occurs when a React component returns an invalid value instead of a valid React element, null, or undefined. React expects components to return JSX elements, but sometimes components accidentally return functions, promises, or forget the return statement entirely.
This warning indicates that a React component's render method or function component body returned a value that React cannot render. React components must return one of the following valid types: - **JSX elements**: Created using JSX syntax like `<div>Hello</div>` or `<Component />` - **null**: When you explicitly want to render nothing - **undefined**: Allowed in React 18+ (automatically treated as rendering nothing) - **Arrays or Fragments**: To return multiple elements - **Strings or numbers**: Rendered as text nodes - **Booleans**: Not displayed (useful for conditional rendering) The warning appears when you return something outside these types, such as a function reference (without calling it), a Promise, a plain object, or when you completely forget to include a return statement. This is a development-mode warning that helps catch bugs before they cause runtime errors. In older versions of React (before 18), returning undefined would cause a runtime error. React 18 relaxed this restriction, allowing components to return undefined, but other invalid return types still trigger this warning.
If you're using a function component with a block body, ensure you have an explicit return statement:
// ❌ Wrong - missing return
function MyComponent() {
<div>Hello World</div>
}
// ✅ Correct - explicit return
function MyComponent() {
return <div>Hello World</div>;
}If you're using an arrow function with implicit return, make sure you're using parentheses correctly:
// ❌ Wrong - curly braces create a block, no implicit return
const MyComponent = () => {
<div>Hello World</div>
};
// ✅ Correct - parentheses allow implicit return
const MyComponent = () => (
<div>Hello World</div>
);
// ✅ Also correct - explicit return with curly braces
const MyComponent = () => {
return <div>Hello World</div>;
};Make sure you're rendering components with angle brackets, not passing them as references:
// ❌ Wrong - returning function reference
function ParentComponent() {
return ChildComponent; // Returns the function itself
}
// ✅ Correct - returning JSX element
function ParentComponent() {
return <ChildComponent />; // Returns rendered component
}This also applies to conditional rendering:
// ❌ Wrong
function MyComponent({ showChild }) {
return showChild ? ChildComponent : null;
}
// ✅ Correct
function MyComponent({ showChild }) {
return showChild ? <ChildComponent /> : null;
}React components cannot directly return Promises. Use state and effects for async operations:
// ❌ Wrong - async component returns Promise
async function MyComponent() {
const data = await fetchData();
return <div>{data}</div>;
}
// ✅ Correct - use state and useEffect
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(setData);
}, []);
if (!data) return <div>Loading...</div>;
return <div>{data}</div>;
}For React 18+ with Suspense, you can use Server Components or specialized data fetching libraries that support Suspense.
All branches of your conditional logic must return valid React elements, null, or undefined:
// ❌ Wrong - might return undefined object property
function MyComponent({ user }) {
return user.profile; // If profile is undefined or an object
}
// ✅ Correct - explicit null check
function MyComponent({ user }) {
if (!user?.profile) return null;
return <div>{user.profile.name}</div>;
}Watch out for logical operators:
// ❌ Wrong - might return 0 or empty string
function MyComponent({ count }) {
return count && <div>Count: {count}</div>;
}
// ✅ Correct - explicit boolean conversion
function MyComponent({ count }) {
return count > 0 ? <div>Count: {count}</div> : null;
}When using arrow functions, be careful with curly braces vs parentheses:
// ❌ Wrong - curly braces create block scope, no return
const MyComponent = () => {
<div>Hello</div>
};
// ✅ Correct - parentheses enable implicit return
const MyComponent = () => (
<div>Hello</div>
);
// ✅ Also correct - explicit return with curly braces
const MyComponent = () => {
return <div>Hello</div>;
};For multi-line JSX, use parentheses:
// ✅ Correct - wrap multi-line JSX in parentheses
const MyComponent = () => (
<div>
<h1>Title</h1>
<p>Content</p>
</div>
);If using TypeScript, ensure your component has the correct return type:
// ❌ Wrong - might allow invalid return types
function MyComponent(): any {
return someInvalidValue;
}
// ✅ Correct - explicit JSX.Element return type
function MyComponent(): JSX.Element {
return <div>Hello</div>;
}
// ✅ Also correct - allow null for conditional rendering
function MyComponent(): JSX.Element | null {
if (someCondition) return null;
return <div>Hello</div>;
}
// ✅ Most flexible - ReactElement covers all valid returns
import { ReactElement } from 'react';
function MyComponent(): ReactElement | null {
return <div>Hello</div>;
}Use React's built-in types for consistency:
import { FC, ReactNode } from 'react';
// Using FC (Function Component) type
const MyComponent: FC = () => {
return <div>Hello</div>;
};
// For components that accept children
const MyComponent: FC<{ children: ReactNode }> = ({ children }) => {
return <div>{children}</div>;
};React 18 Changes: React 18 relaxed the restriction on returning undefined from components. In earlier versions, returning undefined would throw a runtime error, but React 18 treats it the same as returning null. However, other invalid return types (functions, Promises, plain objects) still cause warnings.
Common Pattern Mistakes:
1. Map without return: When using .map() to render lists, forgetting to return JSX is a common error:
// ❌ Wrong
items.map(item => {
<li key={item.id}>{item.name}</li>
})
// ✅ Correct
items.map(item => (
<li key={item.id}>{item.name}</li>
))2. Higher-Order Components: When creating HOCs, ensure you're returning a component, not calling it:
// ❌ Wrong
function withAuth(Component) {
return Component(); // Calling component as function
}
// ✅ Correct
function withAuth(Component) {
return (props) => <Component {...props} />;
}3. Event handlers vs render functions: Don't confuse event handlers (which can return anything) with render functions:
// This is fine - event handlers don't need to return ReactElements
const handleClick = () => {
console.log('clicked');
return false;
};
// But component render must return valid React node
const MyComponent = () => {
return <button onClick={handleClick}>Click</button>;
};TypeScript strict mode: If you enable strict TypeScript settings, the type checker will catch most of these errors at compile time. Consider adding these to your tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}ESLint rules: The react/display-name and react/jsx-no-useless-fragment rules can help catch related issues. Consider using eslint-plugin-react with recommended settings.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite