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

Ram*_*era 26 typescript reactjs

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

这是我的文件夹结构

TodoApp.tsx

function TodoApp() {
  return (
    <Body>
      <AppDiv>
        <Form />
        <Todos />
        <Footer />
      </AppDiv>
    </Body>
  );
}
Run Code Online (Sandbox Code Playgroud)

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>
    </>
  ));
}
Run Code Online (Sandbox Code Playgroud)

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>
    );
  }
};
Run Code Online (Sandbox Code Playgroud)

TodoProps 接口如下:

interface TodoProps {
  text: string;
  completed: boolean;
  id: string;
}
Run Code Online (Sandbox Code Playgroud)

已经尝试过用碎片包裹地图项目的修复,但我仍然无法让它工作。到目前为止,解决问题的唯一方法是在顶部声明Todos.tsxfunction Todos(): any

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

Or *_*ash 156

添加以下代码

"paths": {
   "react": [ "./node_modules/@types/react" ]
 }
Run Code Online (Sandbox Code Playgroud)

tsconfig.json文件,在编译器选项中

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

{
  "compilerOptions": {
    "jsx":"react",
    "strict": true,
    "paths": {
      "react": [ "./node_modules/@types/react" ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这对我来说不起作用。 (2认同)

Ale*_*yne 48

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>
    </>
  )
}
Run Code Online (Sandbox Code Playgroud)

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>)
  }</>
}
Run Code Online (Sandbox Code Playgroud)

You nest all returned JSX in one single fragment.

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

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 />
Run Code Online (Sandbox Code Playgroud)

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

操场

  • @AlexWayne 并不完全正确。从文档中: &gt; React 组件还可以返回元素数组。似乎是 TypeScript / 类型问题:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20356 和 https://github.com/microsoft/TypeScript/issues/21699 (4认同)
  • 好吧,这解决了。但出于好奇,为什么使用普通 React 我可以返回一个数组并且它工作得很好,但是使用 TS,我必须指定它是单个 React 元素? (2认同)

Dan*_*cki 35

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

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

"resolutions": {
  "@types/react": "^17.0.38"
}
Run Code Online (Sandbox Code Playgroud)


Pri*_*tam 14

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

“allowSyntheticDefaultImports”:true


Noa*_*oah 11

我面临着与此错误相同的问题。我将以下代码添加到我的package.json文件中。

"resolutions": {
  "@types/react": "17.0.2",
  "@types/react-dom": "17.0.2",
},
Run Code Online (Sandbox Code Playgroud)

然后,yarn install在终端上运行。

这个对我有用。

  • `graphql` 在这里似乎是多余的 (4认同)

him*_*yan 7

您需要返回一个 JSX 元素,而不是一个数组。包装整个组件是一种解决方案,但您需要在 map/filter 函数之外进行。

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 />)}</>
  );
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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

\n

例如:

\n
switch (loading) {\n    case "pending":\n      return <span>Pending</span>;\n    case "succeeded":\n      return <span>Succeeded</span>;\n    case "failed":\n      return <span>Failed</span>;\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
default: return <span>\xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf</span>;\n
Run Code Online (Sandbox Code Playgroud)\n