翻译:刘小夕javascript
原文连接:dmitripavlutin.com/7-architect…html
原文的篇幅很是长,不过内容太过于吸引我,仍是忍不住要翻译出来。此篇文章对编写可重用和可维护的React组件很是有帮助。但由于篇幅实在太长,我对文章进行了分割,本篇文章重点阐述 组合和复用。因水平有限,文中部分翻译可能不够准确,若是你有更好的想法,欢迎在评论区指出。前端
更多文章可戳: github.com/YvetteLau/B…java
———————————————我是一条分割线————————————————react
一个组合式组件是由更小的特定组件组合而成的。git
组合(composition)是一种经过将各组件联合在一块儿以建立更大组件的方式。组合是 React 的核心。github
幸运的是,组合易于理解。把一组小的片断,联合起来,建立一个更大个儿。redux
让咱们来看一个常见的前端应用组合模式。应用由头部的 header
、底部的 footer
、左侧的 sidebar
,还有中部的有效内容联合而成:react-router
<div id="root"></div>
复制代码
function Application({ children }) {
return (
<div className="application box"> <Label>Application</Label> {children} </div>
);
}
function Header() {
return (
<div className="header box"> <Label>Header</Label> </div>
)
}
function Footer() {
return (
<div className="header box"> <Label>Footer</Label> </div>
)
}
function Sidebar({ children }) {
return (
<div className="sidebar box"> <Label>Sidebar</Label> {children} </div>
);
}
function Content({ children }) {
return (
<div className="content box"> <Label>Content</Label> {children} </div>
)
}
function Menu() {
return (
<div className="menu box">
<Label>Menu</Label>
<div className="description">
<div className="text shorter" />
<div className="text" />
<div className="text shorter" />
<div className="text shorter" />
</div>
</div>
);
}
function Article() {
return (
<div className="article box">
<Label>Article</Label>
<div className="description">
<div className="text shorter" /> <div className="text longer" />
<div className="text shorter" /> <div className="text" />
<div className="text shorter" /> <div className="text" />
<div className="text" /> <div className="text shorter" />
<div className="text shorter" /> <div className="text" />
<div className="text" /> <div className="text shorter" />
<div className="text shorter" /> <div className="text longer" />
<div className="text shorter" /> <div className="longer" />
<div className="text shorter" /> <div className="text" />
<div className="text" /> <div className="text shorter" />
<div className="text shorter" /> <div className="text" />
</div>
</div>
);
}
function Label({ children }) {
return <div className="label"><{children}></div>
}
const app = (
<Application>
<Header />
<Sidebar>
<Menu />
</Sidebar>
<Content>
<Article />
</Content>
<Footer />
</Application>
);
ReactDOM.render(app, document.getElementById('root'));
复制代码
应用程序演示了组合如何构建应用程序。这种组织这样组织代码即富于表现力又便于理解。app
React 组件的组合是天然而然的。这个库使用了一个声明范式,从而不会抑制组合式的表现力。
<Application>
由 <Header>
、 <Sidebar>
<Content>
和 <Footer>
组成. <Sidebar>
有一个 <Menu>
组件, <Content>
有一个 <Article>
组件.
那么组合与单一责任以及封装有什么联系呢?让咱们一块儿看看:
组合的一个重要方面在于可以从特定的小组件组成复杂组件的能力。这种分而治之的方式帮助了被组合而成的复杂组件也能符合 SRP 原则。
回顾以前的代码片断,<Application>
负责渲染 header
、footer
、sidebar
和主体区域。
将此职责分为四个子职责是有意义的,每一个子职责由专门的组件实现,分别是<header>
、<sidebar>
、<content>
和 <footer>
。随后,这些组件被粘合在 <Application>
。
如今来看看组合的好处:经过子组件分别实现单一职责的方式,使 <Application>
组件也符合单一责任原则。
组合有可重用的有点,使用组合的组件能够重用公共逻辑,
例如,组件 <Composed1>
和 <Composed2>
有一些公共代码:
const instance1 = (
<Composed1> /* Specific to Composed1 code... */ /* Common code... */ </Composed1>
);
const instance2 = (
<Composed2> /* Common code... */ /* Specific to Composed2 code... */ </Composed2>
);
复制代码
代码复制是一个很差的实践(例如更改 Composed1
的代码时,也须要去更改Composed2
中的代码),那么如何使组件重用公共代码?
首先,将共同代码封装到一个新组件中,如 <Common>
中,而后
首先,在新组件中封装公共代码。其次,<Composed1>
和 <Composed2>
应该使用组合的方式来包含 <Common>
组件,以免代码重复,以下:
const instance1 = (
<Composed1> <Piece1 /> <Common /> </Composed1>
);
const instance2 = (
<Composed2> <Common /> <Piece2 /> </Composed2>
);
复制代码
可重用的组件符合不重复本身(Don't repeat yourself
)的原则。这种作法能够节省你的精力和时间,而且在后期,有利于代码维护。
在 react
中,一个组合式的组件经过给子组件传递 props
的方式,来控制其子组件。这就带来了灵活性的好处。
例如,有一个组件,它须要根据用户的设备显示信息,使用组合能够灵活地实现这个需求:
function ByDevice({ children: { mobile, other } }) {
return Utils.isMobile() ? mobile : other;
}
<ByDevice>{{
mobile: <div>Mobile detected!</div>,
other: <div>Not a mobile device</div>
}}</ByDevice>
复制代码
<ByDevice>
组合组件,对于移动设备,显示: Mobile detected!
; 对于非移动设备,显示 Not a mobile device"
。
用户界面可组合的层次结构,所以,组件的组合是一种构建用户界面的有效的方式。
注:DRY
原则理论上来讲是没有问题的,但在实际应用是切忌死搬教条。它只能起指导做用,没有量化标准,不然的话理论上一个程序每一行代码都只能出现一次才行,这是很是荒谬的,其它的原则也是同样,起到的也只是指导性的做用。
可重用的组件,一次编写屡次使用。
想象一下,若是软件开发老是重复造轮子。那么当你编写代码时,不能使用任何已有库或工具。甚至在同一个应用中你都不能使用已经编写过的代码。在这种环境中,是否有可能在合理的时间内编写出一个应用呢?绝无可能。
此时应该到认识重用的重要性,使用已有的库或代码,而不是重复造轮子。
根据“不要重复本身”(DRY
)原则,每一条知识都必须在系统中具备单一,明确,权威的表示。这个原则建议避免重复。
代码重复增长了复杂性和维护工做,但没有增长显著的价值。逻辑更新迫使您修改应用程序中的全部重复代码。
重复问题能够用可复用组件来解决。一次编写,屡次使用。
可是,复用并不是毫无成本。只有一个组件符合单一责任原则而且具备合理的封装时,它是可复用的。
符合单一职责原则是必须的:
复用一个组件实际上就意味着复用其职责
只有一个职责的组件是最容易复用的。
可是,当一个组件错误地具备多个职责时,它的复用会增长大量的开销。你只想复用一个职责实现,但也会获得没必要要的职责实现。好比,你只是想要一个香蕉,可是在你获得一个香蕉的同时,不得不被迫接受全部的丛林。
合理封装的组件。隐藏了内部实现,而且有明确的 props
,使得组件可使用与多种须要复用的场合。
某个工做日,你刚刚收到了为应用增长新特性的任务,在撩起袖子狂敲代码以前,先稍等几分钟。
你要作的工做在很大几率上已经被解决了。因为 React
很是流行以及其很是棒的开源社区,先搜索一下是否有已存在的解决方案是明智之举。
查看 brillout/awesome-react-components
,它有一个可复用的组件列表。
优秀的第三方库有结构性的影响,而且会推广最佳实践。以个人经验而言,最有影响的当属 react-router
和 redux
。
react-router
使用了声明式的路由来构建一个单页应用。使用 <Route>
将 URL
和组件关联起来。当用户访问匹配的 URL
时,路由将渲染相应的组件。
redux
和 react-redux
引入了单向和可预测的应用状态管理。能够将异步的和非纯的代码(例如 HTTP
请求)从组件中提取出来,从而符合单一职责原则并建立出 纯(pure)组件 或 几乎纯(almost-pure)的组件。
这里是一份检查清单能够肯定第三方库是否值得使用,:
README.md
文件和详细的文档最后谢谢各位小伙伴愿意花费宝贵的时间阅读本文,若是本文给了您一点帮助或者是启发,请不要吝啬你的赞和Star,您的确定是我前进的最大动力。github.com/YvetteLau/B…