- 原文地址:Defining Component APIs in React
- 原文做者:Jxnblk
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:Gavin-Gong
- 校对者:xunge0613 sunui
多年来,我致力于一系列处理组件 API 和构建应用程序、库的模式。如下是一系列如何设计组件 API 的想法、观点和建议,这会让组件更灵活、更具备组合性、更容易理解。这些规则都不是硬性的,但它们帮助我想明白了如何组织和建立组件。html
正如 React 库自己的目标是 最少化 API 同样,我建议在设计组件 API 时采用相似的观点。须要学习的新内容越少,其余人就越容易知道如何使用你建立的组件,从而使它们更容易被重用。若是有人不理解你的组件 API,那么他们重复你的工做的可能性就会增长。这是我如何建立组件的核心理念,我发如今我工做中牢记它颇有帮助。前端
从扁平目录结构开始,不要过早地组织代码库。人类喜欢整理东西,但咱们在这方面作得很糟糕。命名已经足够困难了,为组件库建立目录结构,您可能会作更多的工做,最终使其余人更难找到你所写的代码。react
一个单独存放组件的目录在变得难以管理以前会变得至关大。若是全部的组件都在一个文件夹中,在大多数文件系统工具中会自动按照字母进行排序,这有助于为其余人提供更完整的代码库概览。android
若是您在组件中定义了以 render 开头的自定义方法,那么它极可能应该被定义为自有组件。正如 Chris Biscardi 所说,“高效意味着有有足够的复杂度值得被分解”。React 能明智地决定是否渲染的时机,所以,将这些组件拆分为自有组件,能够帮助 React 更好地运行。ios
// 不要这样写
class Items extends React.Component {
renderItems ({ items }) {
return items.map(item => (
<li key={item.id}> {renderItem(item)} </li>
))
}
renderItem (item) {
return (
<div> {item.name} </div>
)
}
render () {
return (
<ul> {renderItems(this.props) </ul>
)
}
}
复制代码
// 这样写
const ItemList = ({ items }) =>
<ul>
{items.map(item => (
<li key={item.id}>
<Item {...item} />
</li>
)}
</ul>
const Item = ({ name }) =>
<div>{item.name}</div>
class Items extends React.Component {
render () {
const { items } = this.props
return <ItemList items={items} />
}
}
复制代码
一般,组件应该由数据的形状来定义git
既然你常常向用户展现 JSON 数据模型,你会发现,若是你的模型构建正确,你的 UI(以及你的组件结构)会被很好地映射。github
我常常看到 React 新手尝试复制我所说的 "Bootstrap" 组件,即具备视觉边界,但与任何数据结构都没有直接联系的 UI 组件。React 组件和 BEM 风格、基于 CSS 的组件有着不一样的关注点。不该该建立一个须要定制 props 的通用 Card 组件来显示图像、标题和连接,而是为你须要展现的数据建立组件。也许通用的 Card 组件应该是一个接受来自数据库的 product 对象的 ProductCard 组件。数据库
// 不要这样写
<Card
image={product.thumbnail}
title={product.name}
text={product.description}
link={product.permalink}
/>
// 这样写
<ProductCard {...product} />
复制代码
极可能,你须要的 ProductCard 的特定样式并不都是可重用的,并且你可能只在代码库中的一个地方定义了这个样式。在这种状况下,你能够遵循 三次法则。若是你已经在代码库中复制了三次 Card 组件结构,那么将其抽象出自有组件多是值得的。bootstrap
正如 Jenn Creighton 所说,避免 繁多的 props。不要惧怕建立一个新的组件,而不是向组件添加一些任意的 props 和附加的逻辑。例如,Button 组件能够接受不一样颜色、大小和形状的 props,但并不老是须要这么多的 props。后端
// 不要这要写
<Button
variant='secondary'
size='large'
outline
label='Buy Now'
icon='shoppingBag'
onClick={handleClick}
/>
// 这要写
<SecondaryButton
size='large'
onClick={handleClick}>
<Icon name='shoppingBag' /> Buy Now </SecondaryButton>
复制代码
你的需求可能会有所不一样,可是减小组件所需的自定义 props 的数量一般颇有帮助,而且减小 render 函数中的逻辑数量可使代码库更简单,更适合于代码分割。
不要从新发明 props.children
。若是你已经定义了 props 接收不基于数据结构的任意文本字符串,那么最好使用组合。
// 不要这样写
<Header
title='Hello'
subhead='This is a header'
text='And it has arbitrary props'
/>
// 这样写
<Header>
<Heading>Hello</Heading>
<Subhead>This is a header</Subhead>
<Text>And it uses composition</Text>
</Header>
复制代码
若是你熟悉 React,那么你可能已经知道了组合版本组件的 API,它不会像以前那样须要那么多的文档。在你的应用中,你能够将组合版本的组件封装到另外一个与数据结构绑定组件中,并且你可能只须要在代码库中定义一次组件结构。
// 对于一个基于数据的组件而言,这样写颇有用
const PageHeader = ({
title,
description
}) =>
<Header> <Heading>{title}</Heading> <Text>{description}</Text> </Header>
// 理想状况下能够这样使用
<PageHeader {...page} />
复制代码
使用 布尔 props 是一种在组件变量之间进行切换的便捷方式,这颇有吸引力,但它有时会产生一个使人困惑的 API。 查看下面的例子:
<Button primary />
<Button secondary /> 复制代码
下面的状况会发生什么?
<Button primary secondary />
复制代码
若是不深刻到代码库或文档中,就没法理解。相反,试试如下:
<Button variant="primary" />
复制代码
这样须要打更多的字,可是能够说更加具备可读性。
只要有可能,复用其余组件的 props。例如,若是你正在写一个日期选择器,请使用与原生 <input type='date' />
相同的 props。这样将更容易猜想组件是如何运做的,也更容易记住这些 API。
// 不要这样写
<DatePicker
date={date}
onSelect={handleDateChange}
/>
// 这样写
<DatePicker
value={date}
onChange={handleDateChange}
/>
复制代码
Styled System 库鼓励跨多个组件使用并行风格的 props API。例如,color props 对 Rebass 中的全部组件都起做用,最终达到一次学习,处处使用的效果。
// 来自 Rebass 的例子
<Box color='tomato' />
<Heading color='tomato' /> 复制代码
这些只是我本身对如何设计组件 API 的一些想法,它们可能没法知足您的需求。我能给出的最好建议是与你的队友沟通,建立 RFC 和 PR,并尝试 Readme 驱动开发。编写 React 组件很容易。为你的团队建立一个运行良好的组件库花费时间和精力是很是值得的。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。