React TypeScript:如何将FunctionComponent作为属性传递给另一个组件
问题根源分析
两个警告的核心原因:
- 状态更新时机错误:Robots组件直接在函数体中调用
SetInterval,每次组件渲染都会执行这段逻辑,导致渲染过程中触发setRobotArray,违反了React render方法必须是纯函数的规则。 - 组件渲染方式错误:BasicBlocks中直接将
content(一个FunctionComponent)作为React子元素输出,React无法直接渲染函数,必须将其实例化为组件实例。
解决方案
1. 修复BasicBlocks组件(解决组件渲染警告)
调整content的类型定义,并正确实例化组件:
import React from "react"; import BlockStyle from "../styleDefs/blocks.module.css"; interface BasicBlocksProps { title?: string; subtitle?: string; // 改用ElementType兼容函数/类组件,提升通用性 content?: React.ElementType; // 用联合类型约束size,增强类型安全性 size: "large" | "medium" | "small"; center: boolean; } const BasicBlocks: React.FunctionComponent<BasicBlocksProps> = ({ title, subtitle, content: Content, // 重命名为大写开头,符合React组件命名规范 size, center }) => { return ( <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 && <Content />}</div> </div> ); }; export default BasicBlocks;
2. 修复Robots组件(解决状态更新时机警告)
用useEffect包裹定时器逻辑,确保仅在组件挂载时初始化一次:
import React, { useState, useEffect } from "react"; import axios from "axios"; import TableStyle from "../styleDefs/tableStyles.module.css"; import ButtonStyle from "../styleDefs/buttons.module.css"; import { basicBlock2 } from "../styleDefs/styles"; 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>>([]); // 用useEffect包裹定时器,避免重复创建 useEffect(() => { const interval = SetInterval(() => { axios .get("/api/robots/") .then((res) => { setRobotArray(res.data.robots as Array<Robot>); }) .catch((err) => { console.log("error fetching array of robots: " + err); }); }, 1000 * 1); // 组件卸载时清除定时器,防止内存泄漏 return () => clearInterval(interval); }, []); // 空依赖数组,仅在挂载/卸载时执行 const robotRows = robotArray.map((robot) => { const hasBattery = robot["battery"] !== null; return ( <tr key={robot.robot_name}> <td>{robot["robot_name"]}</td> <td>{robot["connected"].toString()}</td> <td>{hasBattery ? robot.battery : "Not Available"}</td> <td>{robot["active_user_first"] || "None"}</td> </tr> ); }); 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}> add robot </button> </div> </div> ); }; return ( <BasicBlocks title="Robot List" subtitle="suck it" size="large" center={false} content={RobotsPage} /> ); }; export default Robots;
额外优化说明
- 类型约束:使用TypeScript联合类型限制
size和robot_type的取值范围,避免无意义的字符串输入。 - 内存泄漏防护:添加定时器清理逻辑,避免组件卸载后定时器继续运行。
- 逻辑修正:调整
hasBattery的判断逻辑,确保电池值为空时显示正确的提示文本。
内容的提问来源于stack exchange,提问作者Cyba
相关产品推荐
相关产品推荐

