组件不能用作 JSX 组件。其返回类型“ Element []”不是有效的 JSX 元素

我当前在 TodoApp.tsx中的 Todos组件上得到以下错误: ‘ Todos’不能用作 JSX 组件。 它的返回类型‘ Element []’不是有效的 JSX 元素。 类型“ Element []”缺少类型“ Element”的以下属性: Type、 props、 key

这是我的文件夹结构

TodoApp.tsx

function TodoApp() {
return (
<Body>
<AppDiv>
<Form />
<Todos />
<Footer />
</AppDiv>
</Body>
);
}

Todos.tsx

function Todos(): JSX.Element[] {
const todos = useSelector((state: RootState) => state.todos);
const footer = useSelector((state: RootState) => state.footer);


if (footer.hideAll) {
if (footer.showCompleted) {
return todos
.filter((todo) => !todo.completed)
.map((todo: any) => (
<>
<ul>
<Todo todo={todo} />
</ul>
</>
));
}
return todos.map((todo) => (
<>
<div>
<Todo todo={todo} />
</div>
</>
));
}


return todos.map(() => (
<>
<div></div>
</>
));
}

Todo.tsx

type Todo = {
todo: TodoProps;
};


const Todo = ({ todo }: Todo) : JSX.Element => {
const [isEditing, edit] = useState<boolean>(false);
const dispatch = useDispatch();


if (!isEditing) {
return (
<TodoDiv>
<Li
key={todo.id}
completed={todo.completed}
onClick={() => dispatch(completeTodo(todo.id))}
// style={{
//   textDecoration: todo.completed ? "line-through" : "none"
// }}
>
{todo.text}
</Li>
<TodoBttns>
<Button edit onClick={() => edit(!isEditing)}>
<img src={editBttn} alt="Edit Button" />
</Button>
<Button delete onClick={() => dispatch(deleteTodo(todo.id))}>
<img src={deleteBttn} alt="Delete Button" />
</Button>
</TodoBttns>
</TodoDiv>
);
} else {
return (
<FormEdit>
<InputForm key={todo.id} {...{ todo, edit }} />
</FormEdit>
);
}
};

TodoProps 界面如下:

interface TodoProps {
text: string;
completed: boolean;
id: string;
}

我已经尝试过用片段包装地图项目的修复方法,但是我还是不能让它工作。现在唯一需要解决的问题是在 Todos.tsx的顶部声明为这个 function Todos(): any

顺便说一句: 我使用的是 Styled 组件,但我不认为这个问题与库有关。

267883 次浏览

A component needs to return a single root element. You can use fragments to package an array of elements as a single element, by using the fragment as that single root element.

So this does nothing:

function Todos(): JSX.Element {
return todos.map(todo => (
<>
<li>{todo.task}</li>
</>
)
}

Because it's now returning an array of [<><li/></>, <><li/></>, ...]. That fragment needs to be the single root element.

You need to use the fragment like this:

function Todos(): JSX.Element {
return <>{
todos.map(todo => <li>{todo.task}</li>)
}</>
}

You nest all returned JSX in one single fragment.

Using that pattern you may end up with somehting like this:

function Todos(): JSX.Element {
const todos = useSelector((state: RootState) => state.todos);
const footer = useSelector((state: RootState) => state.footer);


if (footer.hideAll) {
if (footer.showCompleted) {
return <>{
todos
.filter((todo) => !todo.completed)
.map((todo: any) => (
<ul>
<Todo todo={todo} />
</ul>
))
}</>
}
return <>{
todos.map((todo) => (
<div>
<Todo todo={todo} />
</div>
))
}</>
}


return <>{
todos.map(() => (
<div></div>
))
}</>
}


// Works without error
<Todos />

Note how each return statement returns just one JSX.Element: the fragment.

Playground

You need to return a JSX Element, not an array. Wrapping the whole component is a solution, but you need to do it outside of the map/filter function.

Todos.tsx


function Todos(): JSX.Element {
const todos = useSelector((state: RootState) => state.todos);
const footer = useSelector((state: RootState) => state.footer);


if (footer.hideAll) {
if (footer.showCompleted) {
return (
<>
{todos.filter((todo) => !todo.completed).map((todo: any) => (
<ul>
<Todo todo={todo} />
</ul>
));
}
</>
}
return (
<>
{todos.map((todo) => (
<div>
<Todo todo={todo} />
</div>
));
}
</>
}


return (
<>{todos.map(() => <div />)}</>
);
}

In my case, it was a forgotten import. Basically copy-pasted some of my code and forgot to import one of the components and this was the error message I get.

In case anyone is facing issue with React + Typescript stack, try adding below setting in tsconfig.json. It worked for me.

"allowSyntheticDefaultImports" : true

In my case I forgot to put back ticks after styled(PreviousStyledElement); After I put them the code started to work.

export const MyNewStyledElement = styled(PreviousStyledElement)``;

For a scenario when someone has upgraded to later React, e.g., 16 -> 17 it could start happening.

Now, while looking for @types/react in your project, you could notice many npm packages have @types/react : "*",. The solution to get rid off the problem, in that scenario, would be to add into your package.json:

"resolutions": {
"@types/react": "^17.0.38"
}

I'm facing the same issue about this error. I add the below code to my package.json file.

"resolutions": {
"@types/react": "17.0.2",
"@types/react-dom": "17.0.2",
"graphql": "^16.5.0"
},

Then, Run yarn install on a terminal.

It works for me.

There's a possibility that you have installed (and probably failed) a new package, which could also cause this error.

If that's the case (that you have recently installed and failed or cancelled a package), you can delete node_modules and run npm i or yarn install then try again.

This answer is related to same problem on react-native. Adding typescript to my newly created react-native app and moving App.js to App.tsx, I met the same error for component named Section. The solution for me was a component type React.Fc<{...}>. This is the problematic Section component after the fix when all errors disappeared and my app started as expected.

 import React, { ReactNode } from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
 

import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
 

const Section: React.FC<{
children: ReactNode;
title: string;
}> = ({children, title}) => {
const isDarkMode = useColorScheme() === 'dark';
return (
<View style={styles.sectionContainer}>
<Text
style={[
styles.sectionTitle,
{
color: isDarkMode ? Colors.white : Colors.black,
},
]}>
{title}
</Text>
<Text
style={[
styles.sectionDescription,
{
color: isDarkMode ? Colors.light : Colors.dark,
},
]}>
{children}
</Text>
</View>
);
};

You need to install types for react npm install @types/react or yarn add @types/react

Sometimes this error can occur when you use the switch case syntax to render your component.

For example:

switch (loading) {
case "pending":
return <span>Pending</span>;
case "succeeded":
return <span>Succeeded</span>;
case "failed":
return <span>Failed</span>;

Sometimes your loading status can mistakenly have a value that you didn't specify in the case, so your component will return undefined. Therefore, you should add a default value:

default: return <span>¯\_(ツ)_/¯</span>;

Another common cause of the "Component cannot be used as a JSX component" error is when we return anything other than a JSX element or null from a component, or forget to return a value.

The App component returns undefined because we have placed our return statement on one line and the JSX code on the next without using parentheses.

We aren't allowed to return undefined from a component, so the error occurs.