这是一个 React 中的卡片组件
const Card = props => {
return(
<div className="card">
<h2>{props.title}</h2>
<p>{props.content}</p>
</div>
)
}
它可能非常有用!如果您最终在应用程序中使用了数百次这个东西,那么您就可以非常轻松地重构应用程序中的少量 HTML。由于那里的类名,您已经在 CSS 中拥有了这种能力,但现在您也拥有了 HTML 控制权。感受它。
但是等等。也许这限制了……一个<h2>
?如果在某些用法中它确实应该是一个<h4>
呢?那里的方法是什么?也许是一种 API?
const Card = props => {
return(
<div className="card">
{props.type === "big" && <h2>{props.title}</h2>}
{props.type !== "big" && <h4>{props.title}</h4>}
<p>{props.content}</p>
</div>
)
}
或者我们强制传递一个级别?
const Card = props => {
const HeaderTag = `h${props.level}`;
return(
<div className="card">
<HeaderTag>{props.title}</HeaderTag>
<p>{props.content}</p>
</div>
)
}
或者也许该标题是它自己的组件?
以及围绕该内容的强制段落标签包装器?这有点限制,不是吗?也许它应该是一个<div>
,以便它可以在其中包含任意 HTML,例如多个段落。
const Card = props => {
return(
<div className="card">
<WhateverHeader>{props.title}</WhateverHeader>
<div>{props.content}</div>
</div>
)
}
实际上,为什么要用 props 请求内容?处理子组件可能更容易,尤其是在传入的是 HTML 的情况下。
const Card = props => {
return(
<div className="card">
<WhateverHeader>{props.title}</WhateverHeader>
{children}
</div>
)
}
我们还可以挑战更多假设。例如,卡片仅用于类名……这不应该更灵活吗?
const Card = props => {
const classes = `card ${props.className}`;
return(
<div className={classes}>
<WhateverHeader>{props.title}</WhateverHeader>
{children}
</div>
)
}
我仍然在那里强制使用card
。我们可以删除它,这样就不会假设它,或者构建卡片 API 的另一个方面,提供一种选择退出它的方法。
即使<div>
包装器也是武断的。也许可以传入该标签名称,以便您可以将其变成<section>
或<article>
或任何您想要的。
也许最好什么都不假设,使我们的卡片像这样
const Card = () => {
return(
<>
{children}
</>
)
}
这样,您就可以自由更改任何想要更改的内容。至少这样,它在保持放松的同时具有灵活性,而不是这种“灵活性”
<Card
parentTag="article"
headerLevel="3"
headerTitle="My Card"
contentWrapper="div"
cardVariation="extra-large"
contentContent=""
this=""
little=""
piggy=""
went=""
to=""
market=""
/>
当您同时追求控制和灵活性时,这种极端的 API 化有时会发生。
没有指导的组件模型也可能导致过度组件化,例如
const Card = props => {
return(
<CardWrapperTheme>
<CardWrapper>
<CardTitle />
<CardContent />
<CardFooter />
</CardWrapper>
</CardWrapperTheme>
)
}
可能有充分的理由这样做,或者它可能是组件化的结果,因为它“免费”并且感觉就像在支持它的架构中就是这样做的。
这是一个平衡。如果一个组件过于严格,则存在人们可能不会使用它们的风险,因为它们没有提供他们需要的东西。如果它们过于宽松,人们可能不会使用它们,因为它们没有提供任何价值,而且,即使他们使用了它们,它们也没有提供任何凝聚力。
我在这里没有任何答案,我只是觉得它很有趣。
我觉得最后一种方式要好得多。它为您提供了更好的组合。您可以进行 props 转发和 ref 转发。它被称为“复合组件”——换句话说,React 元素并非旨在独立存在,而是共同组装以构成一个东西——一张卡片。对于具有内部状态的更复杂的组件,您可以使用上下文来传递内容。对于包装器,以及无法决定它应该是 div 还是其他东西,新兴模式是
as
prop,使用方法如下还有很多需要考虑的地方,但是当您将所有内容加起来时,这种复合组件类型的策略确实是我认为构建此类内容的最佳策略。我不是想把它变成一个营销活动,但这就是我们在 Reach 中所做的:https://gist.github.com/ryanflorence/e5c794e6093d16a69fa88d2112a292f7#one-to-one-rendered-dom-element-to-reach-component。值得注意的是,创造“复合组件”一词的人也是制作 Reach 的人(我也与他们合作,完全透明)
不,简单始终是最好的。如果我添加一个卡片组件,那么我希望只导入一个卡片组件。当它所做的只是输出 div 时,我不会导入 cardheader、cardbody、cardwhatever。
如果某些内容非常不同,以至于需要数十亿个子组件,那么它就是另一个组件,仅此而已。
是的!(很有趣)。
感谢这篇文章。
我认为,“我仍然在那里强制使用 card”之前的版本最接近正确的折衷方案。
是的,我同意(尽管根据情况,其他解决方案可能更好)。最近在一个项目中创建一些嵌套的服务器端渲染的 Gutenberg 块时,我最终使用 twig 模板做了几乎完全相同的事情。它为 innerBlocks 和默认提供的 block className 属性提供了良好的灵活性。
我从未使用过 React,因此我无法谈论给出的实际示例……但我觉得这是我在 CSS 中经常处理的事情。
在开发 UI 元素时,总是存在这样的问题:在“这足够灵活,可以在不同区域重复使用”和“这只是 27000 个[插入框架名称]类的声明”之间划线。
例如,考虑 Bootstrap……
那是他们的“卡片”组件。但是,您可以使用仅包含它们的辅助/实用程序类的组件创建非常类似的东西。
完全功能,并且可能是学习如何充分利用这些实用程序类的绝佳方法。但它也过于抽象,以至于不再是组件,而变成了一个大杂烩。
如何创建“AbstractCard”,其中包含您可以想象的所有设置,然后创建具有少量设置的简单常用组件(使用 AbstractCard 内部)?
然后用户可以决定是否要使用非常简单或可配置的组件。