React Typescript:如何将 FunctionComponent 作为 Prop 传递给另一个 FunctionComponent

问题描述 投票:0回答:1

我正在尝试创建一个名为“BasicBlocks”的可重用 FunctionComponent,它具有标题、副标题和内容(这是一个 FunctionComponent)。此内容正在传递到 BasicBlocks,但未呈现。

我收到这些错误: 警告:无法在现有状态转换期间更新(例如在

render
内)。渲染方法应该是 props 和 state 的纯函数。

警告:函数作为 React 子项无效。如果您返回一个组件而不是从渲染中返回,则可能会发生这种情况。或者也许您打算调用此函数而不是返回它。

基本块

import React from "react";
import HomeStyle from "./home.module.css";
import ButtonStyle from "../styleDefs/buttons.module.css";
import BlockStyle from "../styleDefs/blocks.module.css";

interface BasicBlocksProps {
  title?: string;
  subtitle?: string;
  content?: React.FunctionComponent;
  size: string;
  center: boolean;
}

const BasicBlocks: React.FunctionComponent<BasicBlocksProps> = ({ title, subtitle, content, size, center }) => {
  return (

    // middle size
    <div className={size === "large" ? BlockStyle.large :
    size === "medium" ? BlockStyle.medium : BlockStyle.small}>
        {title && <h1 className={center ? BlockStyle.titleCenter : BlockStyle.titleLeft}>{title}</h1>}
        {subtitle && <div className={center ? BlockStyle.subtitleCenter : BlockStyle.subtitleLeft}>{subtitle}</div>}
        <div className={BlockStyle.content}>{content}</div>
    </div>
  );
};

export default BasicBlocks;

import React, { useState } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { SetInterval } from "./utilities";
import { basicBlock2 } from "../styleDefs/styles";
import ButtonStyle from "../styleDefs/buttons.module.css";
import BlockStyle from "../styleDefs/blocks.module.css";
import RobotStyle from "./robots.module.css";
import TableStyle from "../styleDefs/tableStyles.module.css";
import BasicBlocks from "./basicBlocks";

interface Robot {
  robot_name: string;
  connected: boolean;
  battery: number;
  active_user_id: number;
  active_user_first: string;
  active_user_last: string;
  robot_type: "simple" | "lilflo";
}

const Robots: React.FunctionComponent = () => {
  const [robotArray, setRobotArray] = useState<Array<Robot>>([]);

  // Note this is coming from somewhere else, not vanilla
  SetInterval(() => {
    axios
      .get("/api/robots/")
      .then((res) => {
        console.log(res);
        setRobotArray(res.data.robots as Array<Robot>);
      })
      .catch((err) => {
        console.log("error fetching array of robots: " + err);
      });
  }, 1000 * 1);

  const robotRows = robotArray.map((robot) => {
    const canConnect =
      robot["active_user_first"] === null && robot["connected"];
    const hasBattery =
      !(robot["battery"] === null);
    let connectionString;
    if (robot.robot_type === "lilflo") {
      connectionString = `/controller/${robot["robot_name"]}`;
    } else if (robot.robot_type === "simple") {
      connectionString = `/simple-controller/${robot["robot_name"]}`;
    } else {
      return null;
    }
    return (
      <tr key={robot.robot_name}>
        <td >{robot["robot_name"]}</td>
        <td>{robot["connected"].toString()}</td>
        <td>{hasBattery || "Not Available"}</td>
        <td>{robot["active_user_first"]}</td>
      </tr>
    );
  });

  const Page: React.FunctionComponent = () => {
    return (<div>hello</div>);
  }
  const RobotsPage: React.FunctionComponent = () => {
    return (
      <div style={basicBlock2}>
        <table className={TableStyle.table}>
            <thead >
              <tr >
                <th className={TableStyle.tableHead} >Robot Name</th>
                <th className={TableStyle.tableHead} >Connected</th>
                <th className={TableStyle.tableHead} >Battery</th>
                <th className={TableStyle.tableHead} >Active User</th>
              </tr>
            </thead>
          <tbody>{robotRows}</tbody>
        </table>
        <div className={ButtonStyle.buttonWrapperCenter}>
          <button 
          className={ButtonStyle.addButton}
          onClick={(): void => {
            // axios.post("/api/users/logout").then(
            //   () => {
            //     // request succeeded
            //     setLoggedIn(false);
            //     setUserName("");
            //   },
            //   (err) => {
            //     alert("failed to logout: " + err.response.data["error"]);
            //   }
            // );
          }}>
            add robot
          </button>
      </div>
      </div>
    );
  }

  return (
    <BasicBlocks title={"Robot List"} subtitle={"suck it"} size={"large"} center={false} content={Page}> 
      
      
    </BasicBlocks>
    
  );
};

export default Robots;

我尝试将组件类型更改为 React.Component 或 React.ComponentType 但这些不适用于我的语法。另外,我在标准 ReactJS 中尝试了其他与 TypeScript 语法不匹配的方法。

reactjs typescript components react-props
1个回答
0
投票

首先,您可以通过确保变量以大写字母开头并像任何其他组件一样渲染它来渲染变量中的组件。

const MyComponent = component
return <MyComponent />

其次,您不应该使用

React.FunctionComponent
类型。对于您自己的组件来说这不是必需的,并且如果其他人想要传递基于传递的组件,它将排除这些组件。您真正关心的是 您传递的组件不需要任何道具。 您可能需要

React.ComponentType


这引出了这个简化的例子。 (我删除了与您的问题确实不相关的部分,请随时将它们添加回来)。

import React from "react"; interface BasicBlocksProps { title?: string; subtitle?: string; content?: React.ComponentType; } function BasicBlocks({ title, subtitle, content: ContentComponent }: BasicBlocksProps) { return ( <div> {title && <h1>{title}</h1>} {subtitle && <div>{subtitle}</div>} <div>{ContentComponent && <ContentComponent /> }</div> </div> ); };

请注意 
content

如何重新映射到

ContentComponent
局部变量,然后可以使用
<ContentComponent />
进行渲染。

看游乐场

© www.soinside.com 2019 - 2024. All rights reserved.