英文:Mark Brouch 譯文:王下邀月熊
segmentfault.com/a/1190000007553885
在Walmart Labs的産品開發中,我們進行了大量的Code Review工作,這也保證了我有機會從很多優秀的工程師的代碼中學習他們的代碼風格與樣式。在這篇博文裡我會分享出我最欣賞的五種元件模式與代碼片。不過我首先還是要談談為什麼我們需要執着于提高代碼的閱讀體驗。就好像你有很多種方式去裝扮一隻貓,如果你把你的愛貓裝扮成了如下這樣子:
你或許可以認為蘿蔔青菜各有所愛,但是代碼本身是應當保證其可讀性,特别是在一個團隊中,你的代碼是注定要被其他人閱讀的。電腦是不會在意這些的,不管你朝它們扔過去什麼,它們都會老老實實的解釋,但是你的隊友們可不會這樣,他們會把醜陋的代碼扔回到你的臉上。而所謂的Pretty Components,應該包含如下的特性:
- 即使沒有任何注釋的情況下也易于了解
- 比亂麻般的代碼有更好的性能表現
- 更易于進行Bug追溯
- 簡潔明了,一句頂一萬句
SFC:Stateless Functional Component
我覺得我們在開發中經常忽略掉的一個模式就是所謂的Stateless Functional Component,不過這是我個人最愛的React元件優化模式,沒有之一。我喜愛這種模式不僅僅因為它們能夠減少大量的模闆代碼,而且因為它們能夠有效地提高元件的性能表現。總而言之,SFC能夠讓你的應用跑的更快,長的更帥。
直覺來看,SFC就是指那些僅有一個渲染函數的元件,不過這簡單的改變就可以避免很多的無意義的檢測與記憶體配置設定。下面我們來看一個實踐的例子來看下SFC的具體作用,譬如:
如果我們用正統的React元件的寫法,可以得出如下代碼:
export default class RelatedSearch extends React.Component {
constructor(props) {
super(props);
this._handleClick = this._handleClick.bind(this);
}
_handleClick(suggestedUrl, event) {
event.preventDefault();
this.props.onClick(suggestedUrl);
render() {
return (
<section className="related-search-container">
<h1 className="related-search-title">Related Searches:</h1>
<Layout x-small={2} small={3} medium={4} padded={true}>
{this.props.relatedQueries.map((query, index) =>
<Link
className="related-search-link"
onClick={(event) =>
this._handleClick(query.searchQuery, event)}
key={index}>
{query.searchText}
</Link>
)}
</Layout>
</section>
);
}
而使用SFC模式的話,大概可以省下29%的代碼:
const _handleClick(suggestedUrl, onClick, event) => {
event.preventDefault();
onClick(suggestedUrl);
};
const RelatedSearch = ({ relatedQueries, onClick }) =>
<section className="related-search-container">
<h1 className="related-search-title">Related Searches:</h1>
<Layout x-small={2} small={3} medium={4} padded={true}>
{relatedQueries.map((query, index) =>
<Link
className="related-search-link"
onClick={(event) =>
_handleClick(query.searchQuery, onClick, event)}
key={index}>
{query.searchText}
</Link>
)}
</Layout>
</section>
export default RelatedSearch;
代碼量的減少主要來源兩個方面:
- 沒有構造函數(5行)
- 以Arrow Function的方式替代Render語句(4行)
實際上,SFC最迷人的地方不僅僅是其代碼量的減少,還有就是對于可讀性的提高。SFC模式本身就是所謂純元件的一種最佳實踐範式,而移除了構造函數并且将_handleClick()這個點選事件回調函數提取出元件外,可以使JSX代碼變得更加純粹。另一個不錯的地方就是SFC以Arrow Function的方式來定義了輸入的Props變量,即以Object Destructring文法來聲明元件所依賴的Props:
這樣不僅能夠使元件的Props更加清晰明确,還能夠避免備援的this.props表達式,進而使代碼的可讀性更好。
最後,我還想要強調下雖然我很推崇SFC,不過也不能濫用它。最合适使用SFC的地方就是之前你用純元件的地方。在Walmart Labs中,我們使用Redux來管理應用的狀态,也就意味着我們絕大部分的元件都是純元件,也就給了SFC廣闊的應用空間。一般來說,有以下特征的元件式絕對不适合使用SFC的:
- 需要自定義整個元件的生命周期管理
- 需要使用到refs
Conditional Components
JSX本身不支援if表達式,不過我們可以使用邏輯表達式的方式來避免将代碼切分到不同的子子產品中,大概是如下樣子:
render() {
<div class="search-results-container">
{this.props.isGrid
? <SearchResultsGrid />
: <SearchResultsList />}
</div>
這種表達式在二選一渲染的時候很有效果,不過對于選擇性渲染一個的情況很不友好,譬如如下的情況:
<div class="search-results-list">
{this.props.isSoftSort
? <SoftSortBanner />
: null
}
這樣子确實能起作用,不過看上去感覺怪怪的。我們可以選用另一種更加語義化與友好的方式來實作這個功能,即使用邏輯與表達式然後傳回元件:
{!!this.props.isSoftSort && <SoftSortBanner />}
不過這一點也是見仁見智,每個人按照自己的喜好來就行了。
Arrow Syntax In React And Redux
ES2015裡包含了不少可口的文法糖,我最愛的就是那個Arrow Notation。這個特性在編寫元件時很有作用:
const SoftSort = ({ hardSortUrl, sortByName, onClick }) => {
return (
<div className="SearchInfoMessage">
Showing results sorted by both Relevance and {sortByName}.
<Link
href={`?${hardSortUrl}`}
onClick={(ev) => onClick(ev, hardSortUrl)}>
Sort results by {sortByName} only
</Link>
</div>
);
該函數的功能就是傳回JSX對象,我們也可以忽略return語句:
const SoftSort = ({ hardSortUrl, sortByName, onClick }) =>
<div className="SearchInfoMessage">
Showing results sorted by both Relevance and {sortByName}.
<Link
href={`?${hardSortUrl}`}
onClick={(ev) => onClick(ev, hardSortUrl)}>
Sort results by {sortByName} only
</Link>
代碼行數又少了不少咯!
另一塊我覺得非常适用Arrow Function的地方就是Redux的mapStateToProps函數:
const mapStateToProps = ({isLoading}) => {
return ({
loading: isLoading,
});
需要注意的是,如果你傳回的是Object,你需要包裹在大括号内:
const mapStateToProps = ({isLoading}) => ({
loading: isLoading
});
使用Arrow Function優化的核心點在于其能夠通過專注于函數的重要部分而提升代碼的整體可讀性,并且避免過多的模闆代碼帶來的噪音。
合理使用Object Destructing與Spread Attributes
大的元件往往受困于this.props過長的窘境,典型的如下所示:
<ProductPrice
hidePriceFulfillmentDisplay=
{this.props.hidePriceFulfillmentDisplay}
primaryOffer={this.props.primaryOffer}
productType={this.props.productType}
productPageUrl={this.props.productPageUrl}
inventory={this.props.inventory}
submapType={this.props.submapType}
ppu={this.props.ppu}
isLoggedIn={this.props.isLoggedIn}
gridView={this.props.isGridView}
/>
這麼多的Props估計看着都頭疼,如果我們要将這些Props繼續傳入下一層,大概就要變成下面這個樣子了:
const {
hidePriceFulfillmentDisplay,
primaryOffer,
productType,
productPageUrl,
inventory,
submapType,
ppu,
isLoggedIn,
gridView
} = this.props;
hidePriceFulfillmentDisplay={hidePriceFulfillmentDisplay}
primaryOffer={primaryOffer}
productType={productType}
productPageUrl={productPageUrl}
inventory={inventory}
submapType={submapType}
ppu={ppu}
isLoggedIn={isLoggedIn}
gridView={isGridView}
暫時不考慮unKnown Props,我們可以使用解構指派來實作這個功能:
const props = this.props;
return <ProductPrice {...props} />
Method Definition Shorthand
最後這個方法不一定多有用,不過還是能讓你的代碼變得更加漂亮。如果你希望在Object中添加函數,你可以使用ES2015 Method Definition Shorthand來代替傳統的ES5的表達式,譬如:
如果你想設定一個預設的空方法,也可以利用這種方式:
ProductRating.defaultProps = {
onStarsClick() {}
本文作者:前端大全
本文釋出時間:2018年03月14日
本文來自雲栖社群合作夥伴
CSDN,了解相關資訊可以關注csdn.net網站。