繁体   English   中英

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

[英]Component cannot be used as a JSX component. Its return type 'Element[]' is not a valid JSX element

我目前在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;
}

已经尝试用片段包装 map 项目的修复,但我仍然无法使其工作。 到目前为止唯一能解决这个问题的是在Todos.tsx的顶部声明这个function Todos(): any

附带说明:我正在使用样式化组件,但我认为该问题与库无关。

组件需要返回单个根元素。 您可以使用片段将 package 元素数组作为单个元素,通过将片段用作单个根元素。

所以这什么都不做:

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

因为它现在返回[<><li/></>, <><li/></>, ...]的数组。 该片段需要是单个根元素。

您需要像这样使用片段:

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

您将所有返回的 JSX 嵌套在一个片段中。

使用这种模式,你最终可能会得到这样的结果:

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 />

注意每个 return 语句如何只返回一个JSX.Element :片段。

操场

您需要返回一个 JSX 元素,而不是一个数组。 包装整个组件是一种解决方案,但您需要在映射/过滤器 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 />)}</>
  );
}

如果有人遇到 React + Typescript 堆栈的问题,请尝试在 tsconfig.json 中添加以下设置。 它对我有用。

“allowSyntheticDefaultImports”:真

就我而言,这是一个被遗忘的导入。 基本上复制粘贴了我的一些代码并忘记导入其中一个组件,这是我得到的错误消息。

您可能已经安装(并且可能失败)新的 package,这也可能导致此错误。

如果是这种情况(您最近安装并失败或取消了一个包),您可以删除node_modules并运行npm iyarn install然后重试。

您需要为 react 安装类型npm install @types/reactyarn add @types/react

当您使用switch case语法呈现组件时,有时会发生此错误。

例如:

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

有时您的加载状态可能会错误地具有您未在case中指定的值,因此您的组件将返回undefined 因此,您应该添加一个default值:

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

对于有人升级到更高版本的React的场景,例如, 16 -> 17 ,它可能会开始发生。

现在,在您的项目中查找@types/react时,您会注意到许多npm包具有@types/react: "*", 在这种情况下,摆脱问题的解决方案是添加到您的package.json

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

关于这个错误,我面临同样的问题。 我将以下代码添加到我的package.json文件中。

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

然后,在终端上运行yarn install

这个对我有用。

这个答案与 react-native 上的相同问题有关。将 typescript 添加到我新创建的 react-native 应用程序并将 App.js 移动到 App.tsx,我遇到了名为 Section 的组件的相同错误。 我的解决方案是组件类型React.Fc<{...}> 当所有错误都消失并且我的应用程序按预期启动时,这是修复后有问题的部分组件。

 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>
   );
 };

“组件不能用作 JSX 组件”错误的另一个常见原因是当我们从组件返回 JSX 元素或 null 以外的任何内容时,或者忘记返回值。

App 组件返回 undefined ,因为我们将 return 语句放在一行,将 JSX 代码放在下一行,而没有使用括号

我们不允许从组件返回undefined ,所以错误发生了。

添加以下代码

"paths": {
   "react": [ "./node_modules/@types/react" ]
 }

tsconfig.json文件,在 compilerOptions

这是我的代码现在的样子:

{
  "compilerOptions": {
    "jsx":"react",
    "strict": true,
    "paths": {
      "react": [ "./node_modules/@types/react" ]
    }
  }
}

它告诉 typescript 编译器,当遇到对“react”模块的引用时,它应该在“./node_modules/@types/react”目录中查找实际实现。

就我而言,我忘记在styled(PreviousStyledElement);之后放回刻度线。 在我把它们放好之后,代码就开始工作了。

 export const MyNewStyledElement = styled(PreviousStyledElement)``;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM