reactjs - React.cloneElement 和打字稿
问题描述
我正在尝试使用 React 和 Typescript 制作仪表板。我使用 Card 组件通过 React.cloneElement 将子组件推入其中,并添加 Card 的 setStates 以从子级向 Card 添加类和标题。现在添加的 setState 函数出现错误。在示例中,我删除了不必要的代码和类型以使代码更具可读性。例子:
import React, {useState} from 'react'
function App() {
return (
<div>
<Block
id="users-component"
title="Users Table"
>
<MyTable class="users" />
</Block>
<Block
id="status-component"
title="Status Component"
>
<Status class="status" /> {/* Property 'renewTitle' is missing in type '{ class: string; }' but required in type 'IStatus'. */}
</Block>
<Block
id="bdays-component"
title="Bdays Component"
>
<Bdays class="bdays" /> {/* Property 'addClasses' is missing in type '{ class: string; }' but required in type 'IBDays'. */}
</Block>
</div>
)
}
interface IBlock {
children: JSX.Element,
id: string,
title: string
}
function Block(props: IBlock) {
const [classes, addClasses] = useState<string[]>([""])
const [title, renewTitle] = useState<string>(props.title)
return (
<div id={props.id} className={classes.join(" ")}>
<h2>{props.title}</h2>
{React.cloneElement(props.children, {addClasses, renewTitle})}
</div>
)
}
function MyTable(props) {
return (
<table> </table>
)
}
interface IStatus {
class: string,
renewTitle: (title: string) => void // ?
}
function Status(props: IStatus) {
const handleClick = (title) => {
props.renewTitle(title) // changes title in Block
}
return (
<div>
<button onClick={() => handleClick("newTitle")}>New Title</button>
</div>
)
}
interface IBDays {
class: string,
addClasses: (classes: string[]) => void // ?
}
function Bdays(props: IBDays) {
const handleClick = (newClass: string) : void => {
props.addClasses([newClass]) // add new class to array "classes" in it's block
}
return (
<div className={props.class}>
<button onClick={() => handleClick("newClass")}>New Class</button>
</div>
)
}
我该如何解决这些问题?
解决方案
更新
你需要做一个小的重构。TypeScript 无法确定您正在克隆子组件。我改变了一点逻辑。因为它允许children
属性成为一个函数,所以我只是将所需的道具传递给这个函数。
现在 TS 能够弄清楚props
里面的论点{(props) => <Status class="status" {...props} />}
实际上是有效的
请看评论
import React, { useState } from 'react'
function App() {
return (
<div>
<Block
id="users-component"
title="Users Table"
>{() => <MyTable class="users" />}
</Block>
<Block
id="status-component"
title="Status Component"
>{(props) => <Status class="status" {...props} />}
</Block>
<Block
id="bdays-component"
title="Bdays Component"
>
{(props) => <Bdays class="bdays" {...props} />}
</Block>
</div>
)
}
interface IBlock {
children: (
props: {
addClasses: React.Dispatch<React.SetStateAction<string[]>>,
renewTitle: React.Dispatch<React.SetStateAction<string>>
}
) => React.ReactNode
id: string,
title: string
}
const Block: React.FC<IBlock> = (props: IBlock) => {
const [classes, addClasses] = useState<string[]>([""])
const [title, renewTitle] = useState<string>(props.title)
return (
<div id={props.id} className={classes.join(" ")}>
<h2>{props.title}</h2>
{props.children({ addClasses, renewTitle })}
</div>
)
}
function MyTable(props: { class: string }) {
return (
<table> </table>
)
}
interface IStatus {
class: string,
renewTitle: (title: string) => void
}
function Status(props: IStatus) {
const handleClick = (title: string) => {
props.renewTitle(title)
}
return (
<div>
<button onClick={() => handleClick("newTitle")}>New Title</button>
</div>
)
}
interface IBDays {
class: string,
addClasses: (classes: string[]) => void
}
function Bdays(props: IBDays) {
const handleClick = (newClass: string): void => {
props.addClasses([newClass])
}
return (
<div className={props.class}>
<button onClick={() => handleClick("newClass")}>New Class</button>
</div>
)
}
推荐阅读
- amazon-web-services - IntelliJ:为 gradle 运行配置设置 AWS 环境变量
- rust - 将宏参数传递给其他宏
- excel - VBA 在下一个可用行中插入数据,该行不是工作表底部的总行
- python-3.x - 从 Scrapy 获取统计信息的 Python Telegram 机器人
- video - 负数或 0 秒持续时间
- javascript - Javascript - 您如何通过添加数字使记录唯一?
- javascript - 将EventListener 添加到innerHTML
- javascript - 我在我的 html 页面上得到了这个 [object HTMLSpanElement]
- entity-framework - EF(在 WPF 中)第一次使用时不创建数据库(CreateDatabaseIfNotExists 不起作用)
- asp.net-core - Identity Server 4 没有为 `.well-known/openid-configuration` 设置`Access-Control-Allow-Origin`