成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React 組件設(shè)計(jì)和分解思考

liukai90 / 2409人閱讀

摘要:我們可以在組件的設(shè)計(jì)上,玩轉(zhuǎn)出很多花樣。但是,如何對(duì)一個(gè)功能復(fù)雜且臃腫的組件進(jìn)行分解,也許并不是一件簡(jiǎn)單的事情。同時(shí),借助于新的算法引擎,兩個(gè)單元組件在渲染的效率上,樂(lè)觀地預(yù)計(jì)會(huì)有較大幅度的提升。

之前分享過(guò)幾篇關(guān)于React技術(shù)棧的文章:

做出Uber移動(dòng)網(wǎng)頁(yè)版還不夠 極致性能打造才見(jiàn)真章

解析Twitter前端架構(gòu) 學(xué)習(xí)復(fù)雜場(chǎng)景數(shù)據(jù)設(shè)計(jì)

React Conf 2017 干貨總結(jié)1: React + ES next = ?

React+Redux打造“NEWS EARLY”單頁(yè)應(yīng)用 一個(gè)項(xiàng)目理解最前沿技術(shù)棧真諦

一個(gè)react+redux工程實(shí)例

......

今天再來(lái)同大家討論 React 組件設(shè)計(jì)的一個(gè)有趣話題:分解 React 組件的幾種進(jìn)階方法。

React 組件魔力無(wú)窮,同時(shí)靈活性超強(qiáng)。我們可以在組件的設(shè)計(jì)上,玩轉(zhuǎn)出很多花樣。但是保證組件的Single responsibility principle: 單一原則非常重要,它可以使得我們的組件更簡(jiǎn)單、更方便維護(hù),更重要的是使得組件更加具有復(fù)用性。

但是,如何對(duì)一個(gè)功能復(fù)雜且臃腫的 React 組件進(jìn)行分解,也許并不是一件簡(jiǎn)單的事情。本文由淺入深,介紹三個(gè)分解 React 組件的方法。

切割 render() 方法

這是一個(gè)最容易想到的方法:當(dāng)一個(gè)組件渲染了很多元素時(shí),就需要嘗試分離這些元素的渲染邏輯。最迅速的方式就是切割 render() 方法為多個(gè) sub-render 方法。

看下面的例子會(huì)更加直觀:

class Panel extends React.Component {
  renderHeading() {
    // ...
  }

  renderBody() {
    // ...
  }

  render() {
    return (
      
{this.renderHeading()} {this.renderBody()}
); }

細(xì)心的讀者很快就能發(fā)現(xiàn),其實(shí)這并沒(méi)有分解組件本身,該 Panel 組件仍然保持有原先的 state, props, 以及 class methods。

如何真正地做到減少?gòu)?fù)雜度呢?我們需要?jiǎng)?chuàng)建一些子組件。此時(shí),采用最新版 React 支持并推薦的函數(shù)式組件/無(wú)狀態(tài)組件一定會(huì)是一個(gè)很好的嘗試:

const PanelHeader = (props) => (
  // ...
);

const PanelBody = (props) => (
  // ...
);

class Panel extends React.Component {
  render() {
    return (
      
// Nice and explicit about which props are used
); } }

同之前的方式相比,這個(gè)微妙的改進(jìn)是革命性的。我們新建了兩個(gè)單元組件:PanelHeader 和 PanelBody。這樣帶來(lái)了測(cè)試的便利,我們可以直接分離測(cè)試不同的組件。同時(shí),借助于 React 新的算法引擎 React Fiber,兩個(gè)單元組件在渲染的效率上,樂(lè)觀地預(yù)計(jì)會(huì)有較大幅度的提升。

模版化組件

回到問(wèn)題的起點(diǎn),為什么一個(gè)組件會(huì)變的臃腫而復(fù)雜呢?其一是渲染元素較多且嵌套,另外就是組件內(nèi)部變化較多,或者存在多種 configurations 的情況。

此時(shí),我們便可以將組件改造為模版:父組件類似一個(gè)模版,只專注于各種 configurations。

還是要舉例來(lái)說(shuō),這樣理解起來(lái)更加清晰。

比如我們有一個(gè) Comment 組件,這個(gè)組件存在多種行為或事件。同時(shí)組件所展現(xiàn)的信息根據(jù)用戶的身份不同而有所變化:用戶是否是此 comment 的作者,此 comment 是否被正確保存,各種權(quán)限不同等等都會(huì)引起這個(gè)組件的不同展示行為。這時(shí)候,與其把所有的邏輯混淆在一起,也許更好的做法是利用 React 可以傳遞 React element 的特性,我們將 React element 進(jìn)行組件間傳遞,這樣就更加像一個(gè)模版:

class CommentTemplate extends React.Component {
  static propTypes = {
    // Declare slots as type node
    metadata: PropTypes.node,
    actions: PropTypes.node,
  };
  
  render() {
    return (
      
// Slot for metadata {this.props.metadata} // Slot for actions {this.props.actions}
...

此時(shí),我們真正的 Comment 組件組織為:

class Comment extends React.Component {
  render() {
    const metadata = this.props.publishTime ?
       :
      Saving...;
    
    const actions = [];
    if (this.props.isSignedIn) {
      actions.push();
      actions.push();
    }
    if (this.props.isAuthor) {
      actions.push();
    }
    
    return ;
  }
  

metadata 和 actions 其實(shí)就是在特定情況下需要渲染的 React element。

比如,如果 this.props.publishTime 存在,metadata 就是 ;反正則為 Saving...。

如果用戶已經(jīng)登陸,則需要渲染(即actions值為) ,如果是作者本身,需要渲染的內(nèi)容就要加入 。

高階組件

在實(shí)際開(kāi)發(fā)當(dāng)中,組件經(jīng)常會(huì)被其他需求所污染。

比如,我們想統(tǒng)計(jì)頁(yè)面中所有鏈接的點(diǎn)擊信息。在鏈接點(diǎn)擊時(shí),發(fā)送統(tǒng)計(jì)請(qǐng)求,同時(shí)包含此頁(yè)面 document 的 id 值。常見(jiàn)的做法是在 Document 組件的生命周期函數(shù) componentDidMount 和 componentWillUnmount 增加代碼邏輯:

class Document extends React.Component {
  componentDidMount() {
    ReactDOM.findDOMNode(this).addEventListener("click", this.onClick);
  }
  
  componentWillUnmount() {
    ReactDOM.findDOMNode(this).removeEventListener("click", this.onClick);
  }
  
  onClick = (e) => {
    if (e.target.tagName === "A") { // Naive check for  elements
      sendAnalytics("link clicked", {
        documentId: this.props.documentId // Specific information to be sent
      });
    }
  };
  
  render() {
    // ...
    

這么做的幾個(gè)問(wèn)題在于:

相關(guān)組件 Document 除了自身的主要邏輯:顯示主頁(yè)面之外,多了其他統(tǒng)計(jì)邏輯;

如果 Document 組件的生命周期函數(shù)中,還存在其他邏輯,那么這個(gè)組件就會(huì)變的更加含糊不合理;

統(tǒng)計(jì)邏輯代碼無(wú)法復(fù)用;

組件重構(gòu)、維護(hù)都會(huì)變的更加困難。

為了解決這個(gè)問(wèn)題,我們提出了高階組件這個(gè)概念: higher-order components (HOCs)。不去晦澀地解釋這個(gè)名詞,我們來(lái)直接看看使用高階組件如何來(lái)重構(gòu)上面的代碼:

function withLinkAnalytics(mapPropsToData, WrappedComponent) {
  class LinkAnalyticsWrapper extends React.Component {
    componentDidMount() {
      ReactDOM.findDOMNode(this).addEventListener("click", this.onClick);
    }

    componentWillUnmount() {
      ReactDOM.findDOMNode(this).removeEventListener("click", this.onClick);
    }

    onClick = (e) => {
      if (e.target.tagName === "A") { // Naive check for  elements
        const data = mapPropsToData ? mapPropsToData(this.props) : {};
        sendAnalytics("link clicked", data);
      }
    };
    
    render() {
      // Simply render the WrappedComponent with all props
      return ;
    }
  }

需要注意的是,withLinkAnalytics 函數(shù)并不會(huì)去改變 WrappedComponent 組件本身,更不會(huì)去改變 WrappedComponent 組件的行為。而是返回了一個(gè)被包裹的新組件。實(shí)際用法為:

class Document extends React.Component {
  render() {
    // ...
  }
}

export default withLinkAnalytics((props) => ({
  documentId: props.documentId
}), Document);

這樣一來(lái),Document 組件仍然只需關(guān)心自己該關(guān)心的部分,而 withLinkAnalytics 賦予了復(fù)用統(tǒng)計(jì)邏輯的能力。

高階組件的存在,完美展示了 React 天生的復(fù)合(compositional)能力,在 React 社區(qū)當(dāng)中,react-redux,styled-components,react-intl 等都普遍采用了這個(gè)方式。值得一提的是,recompose 類庫(kù)又利用高階組件,并發(fā)揚(yáng)光大,做到了“腦洞大開(kāi)”的事情。

總結(jié)

React 及其周邊社區(qū)的崛起,讓函數(shù)式編程風(fēng)靡一時(shí),受到追捧。其中關(guān)于 decomposing 和 composing 的思想,我認(rèn)為非常值得學(xué)習(xí)。同時(shí),對(duì)開(kāi)發(fā)設(shè)計(jì)的一個(gè)建議是,不要猶豫將你的組件拆分的更小、更單一,因?yàn)檫@樣能換來(lái)強(qiáng)健和復(fù)用。

本文意譯了David Tang的:Techniques for decomposing React components一文。

Happy Coding!

PS: 作者Github倉(cāng)庫(kù),歡迎通過(guò)代碼各種形式交流。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83696.html

相關(guān)文章

  • React編程思想

    摘要:的單向數(shù)據(jù)流也稱為單向綁定使所有的事務(wù)更加模塊化也更加快速。第五步添加反向數(shù)據(jù)流到目前為止,我們已經(jīng)構(gòu)建了一個(gè)應(yīng)用程序,可以根據(jù)和正確地呈現(xiàn)在層次結(jié)構(gòu)中。傳遞的回調(diào)將調(diào)用,并且應(yīng)用程序?qū)⒈桓隆? 本文是對(duì)React官網(wǎng)《Thinking in React》一文的翻譯,通過(guò)這篇文章,React團(tuán)隊(duì)向開(kāi)發(fā)者們介紹了應(yīng)該如果去構(gòu)思一個(gè)web應(yīng)用,為今后使用React進(jìn)行web app的構(gòu)建,...

    ckllj 評(píng)論0 收藏0
  • React思維方式·譯

    摘要:搜索文本和多選框因?yàn)闀?huì)發(fā)生變化,且不能通過(guò)計(jì)算得出,所以是狀態(tài)。最后,過(guò)濾過(guò)的產(chǎn)品列表,可以通過(guò)原始產(chǎn)品列表搜索文本和多選框值計(jì)算出來(lái),因此它不是狀態(tài)。從傳入的回調(diào)函數(shù)會(huì)調(diào)用,從而更新組件。 在使用JavaScript開(kāi)發(fā)大型、快速的網(wǎng)頁(yè)應(yīng)用時(shí),React是我們的首選。在Facebook和Instagram,React很好地減少了我們的工作量。React最強(qiáng)大部分之一,是讓你在開(kāi)發(fā)應(yīng)用...

    helloworldcoding 評(píng)論0 收藏0
  • React 設(shè)計(jì)模式場(chǎng)景分析

    摘要:這一周連續(xù)發(fā)表了兩篇關(guān)于的文章組件復(fù)用那些事兒實(shí)現(xiàn)按需加載輪子應(yīng)用設(shè)計(jì)之道化妙用其中涉及到組件復(fù)用輪子設(shè)計(jì)相關(guān)話題,并配合相關(guān)場(chǎng)景實(shí)例進(jìn)行了分析。 showImg(https://segmentfault.com/img/remote/1460000014482098); 這一周連續(xù)發(fā)表了兩篇關(guān)于 React 的文章: 組件復(fù)用那些事兒 - React 實(shí)現(xiàn)按需加載輪子 React ...

    avwu 評(píng)論0 收藏0
  • React 設(shè)計(jì)模式場(chǎng)景分析

    摘要:這一周連續(xù)發(fā)表了兩篇關(guān)于的文章組件復(fù)用那些事兒實(shí)現(xiàn)按需加載輪子應(yīng)用設(shè)計(jì)之道化妙用其中涉及到組件復(fù)用輪子設(shè)計(jì)相關(guān)話題,并配合相關(guān)場(chǎng)景實(shí)例進(jìn)行了分析。 showImg(https://segmentfault.com/img/remote/1460000014482098); 這一周連續(xù)發(fā)表了兩篇關(guān)于 React 的文章: 組件復(fù)用那些事兒 - React 實(shí)現(xiàn)按需加載輪子 React ...

    sshe 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<