组件不能用作 JSX 组件.它的返回类型 'Element[]' 不是有效的 JSX 元素 [英] Component cannot be used as a JSX component. Its return type 'Element[]' is not a valid JSX element

查看:967
本文介绍了组件不能用作 JSX 组件.它的返回类型 'Element[]' 不是有效的 JSX 元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这是我的文件夹结构

TodoApp.tsx

function TodoApp() {返回 (<身体><AppDiv><表格/><待办事项/><页脚/></AppDiv></身体>);}

Todos.tsx

function Todos(): JSX.Element[] {const todos = useSelector((state: RootState) => state.todos);const footer = useSelector((state: RootState) => state.footer);如果(页脚.hideAll){如果(footer.showCompleted){返回待办事项.filter((todo) => !todo.completed).map((todo: any) => (<><ul><Todo todo={todo}/></>));}返回 todos.map((todo) => (<><div><Todo todo={todo}/>

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

Todo.tsx

type Todo = {待办事项:TodoProps;};const Todo = ({ todo }: Todo) : JSX.Element =>{const [isEditing, edit] = useState(false);const dispatch = useDispatch();如果 (!isEditing) {返回 (<TodoDiv><李键={todo.id}完成={todo.completed}onClick={() =>dispatch(completeTodo(todo.id))}//样式={{//textDecoration: todo.completed ?直通":无"//}}>{todo.text}<TodoBttns><按钮编辑 onClick={() =>编辑(!isEditing)}><img src={editBttn} alt=编辑按钮"/></按钮><按钮删除 onClick={() =>dispatch(deleteTodo(todo.id))}><img src={deleteBttn} alt=删除按钮"/></按钮></TodoBttns></TodoDiv>);} 别的 {返回 (<表格编辑><InputForm key={todo.id} {...{ todo, edit }}/></FormEdit>);}};

和 TodoProps 接口如下:

interface TodoProps {文本:字符串;完成:布尔值;id:字符串;}

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

附带说明:我使用的是样式化组件,但我认为问题与库无关.

解决方案

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

所以这什么都不做:

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

因为它现在返回一个 [<>

  • , <><li/></>, ...].该片段必须是单个根元素.

    你需要像这样使用片段:

    function Todos(): JSX.Element {返回 <>{todos.map(todo => 
  • {todo.task}
  • )}</>}

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

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

    function Todos(): JSX.Element {const todos = useSelector((state: RootState) => state.todos);const footer = useSelector((state: RootState) => state.footer);如果(页脚.hideAll){如果(footer.showCompleted){返回 <>{待办事项.filter((todo) => !todo.completed).map((todo: any) => (<ul><Todo todo={todo}/>))}</>}返回 <>{todos.map((todo) => (<div><Todo todo={todo}/>
  • ))}</>}返回 <>{todos.map(() => (<div></div>))}</>}//工作没有错误<待办事项/>

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

    游乐场

    I'm currently getting the following error on the Todos component inside TodoApp.tsx: 'Todos' cannot be used as a JSX component. Its return type 'Element[]' is not a valid JSX element. Type 'Element[]' is missing the following properties from type 'Element': type, props, key

    And this is my folder structure

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

    and the TodoProps interface is the following:

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

    already tried the fix of wraping the map items with fragments, but I still can't make it work. The only thing that as of now is fixing the issue is declaring at the top of Todos.tsx as this function Todos(): any

    As a side note: I'm using Styled Components, but I don't think the issue is related to the library.

    解决方案

    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

    这篇关于组件不能用作 JSX 组件.它的返回类型 'Element[]' 不是有效的 JSX 元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆