国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React組件設計技巧

Luosunce / 1227人閱讀

摘要:我們可以通過剛剛高階函數的思想來創建一個中間組件,也就是我們說的高階組件。僅傳遞組件所需要的屬性。在受控組件中,表單數據由組件負責處理。作為頂層組件接收一個名為的,可以接收任意需要被放入中的字符串,數字,甚至是函數。

React組件設計 組件分類 展示組件和容器組件
展示組件 容器組件
關注事物的展示 關注事物如何工作
可能包含展示和容器組件,并且一般會有DOM標簽和css樣式 可能包含展示和容器組件,并且不會有DOM標簽和css樣式
常常允許通過this.props.children傳遞 提供數據和行為給容器組件或者展示組件
對第三方沒有任何依賴,比如store 或者 flux action 調用flux action 并且提供他們的回調給展示組件
不要指定數據如何加載和變化 作為數據源,通常采用較高階的組件,而不是自己寫,比如React Reduxconnect(), Relay的createContainer(), Flux UtilsContainer.create()
僅通過屬性獲取數據和回調 null
很少有自己的狀態,即使有,也是自己的UI狀態 null
除非他們需要的自己的狀態,生命周期,或性能優化才會被寫為功能組件 null

下面是一個可能會經常寫的組件,評論列表組件,數據交互和展示都放到了一個組件里面。

// CommentList.js
class CommentList extends React.Component {
  constructor() {
    super();
    this.state = { comments: [] }
  }
  componentDidMount() {
    $.ajax({
      url: "/my-comments.json",
      dataType: "json",
      success: function(comments) {
        this.setState({comments: comments});
      }.bind(this)
    });
  }
  render() {
    return 
    {this.state.comments.map(renderComment)}
; } renderComment({body, author}) { return
  • {body}—{author}
  • ; } }

    我們對上面的組件進行拆分,把他拆分成容器組件 CommentListContainer.js 和展示組件 CommentList

    // CommentListContainer.js
    class CommentListContainer extends React.Component {
      constructor() {
        super();
        this.state = { comments: [] }
      }
      componentDidMount() {
        $.ajax({
          url: "/my-comments.json",
          dataType: "json",
          success: function(comments) {
            this.setState({comments: comments});
          }.bind(this)
        });
      }
      render() {
        return ;
      }
    }
    
    
    // CommentList.js
    class CommentList extends React.Component {
      constructor(props) {
        super(props);
      }
      render() { 
        return 
      {this.props.comments.map(renderComment)}
    ; } renderComment({body, author}) { return
  • {body}—{author}
  • ; } }

    優勢:

    展示和容器更好的分離,更好的理解應用程序和UI

    重用性高,展示組件可以用于多個不同的state數據源

    展示組件就是你的調色板,可以把他們放到多帶帶的頁面,在不影響應用程序的情況下,讓設計師調整UI

    迫使你分離標簽,達到更高的可用性

    有狀態組件和無狀態組件

    下面是一個最簡單的無狀態組件的例子:

    function HelloComponent(props, /* context */) {
      return 
    Hello {props.name}
    } ReactDOM.render(, mountNode)

    可以看到,原本需要寫“類”定義(React.createClass 或者 class YourComponent extends React.Component)來創建自己組件的定義(有狀態組件),現在被精簡成了只寫一個 render 函數。更值得一提的是,由于僅僅是一個無狀態函數,React 在渲染的時候也省掉了將“組件類” 實例化的過程。

    結合 ES6 的解構賦值,可以讓代碼更精簡。例如下面這個 Input 組件:

    function Input({ label, name, value, ...props }, { defaultTheme }) {
      const { theme, autoFocus, ...rootProps } = props
      return (
        

    無狀態組件不像上述兩種方法在調用時會創建新實例,它創建時始終保持了一個實例,避免了不必要的檢查和內存分配,做到了內部優化。

    無狀態組件不支持 "ref"
    高階組件

    高階組件通過函數和閉包,改變已有組件的行為,本質上就是 Decorator 模式在 React 的一種實現。

    當寫著寫著無狀態組件的時候,有一天忽然發現需要狀態處理了,那么無需徹底返工:)
    往往我們需要狀態的時候,這個需求是可以重用的。

    高階組件加無狀態組件,則大大增強了整個代碼的可測試性和可維護性。同時不斷“誘使”我們寫出組合性更好的代碼。

    高階函數
    function welcome() {
        let username = localStorage.getItem("username");
        console.log("welcome " + username);
    }
    
    function goodbey() {
        let username = localStorage.getItem("username");
        console.log("goodbey " + username);
    }
    
    welcome();
    goodbey();

    我們發現兩個函數有一句代碼是一樣的,這叫冗余唉。(平時可能會有一大段代碼的冗余)。

    下面我們要寫一個中間函數,讀取username,他來負責把username傳遞給兩個函數。

    function welcome(username) {
        console.log("welcome " + username);
    }
    
    function goodbey(username) {
        console.log("goodbey " + username);
    }
    
    function wrapWithUsername(wrappedFunc) {
        let newFunc = () => {
            let username = localStorage.getItem("username");
            wrappedFunc(username);
        };
        return newFunc;
    }
    
    welcome = wrapWithUsername(welcome);
    goodbey = wrapWithUsername(goodbey);
    
    welcome();
    goodbey();

    好了,我們里面的 wrapWithUsername 函數就是一個“高階函數”。
    他做了什么?他幫我們處理了 username,傳遞給目標函數。我們調用最終的函數 welcome的時候,根本不用關心 username是怎么來的。

    舉一反三的高階組件

    下面是兩個冗余的組件。

    import React, {Component} from "react"
    
    class Welcome extends Component {
        constructor(props) {
            super(props);
            this.state = {
                username: ""
            }
        }
    
        componentWillMount() {
            let username = localStorage.getItem("username");
            this.setState({
                username: username
            })
        }
    
        render() {
            return (
                
    welcome {this.state.username}
    ) } } export default Welcome;
    import React, {Component} from "react"
    
    class Goodbye extends Component {
        constructor(props) {
            super(props);
            this.state = {
                username: ""
            }
        }
    
        componentWillMount() {
            let username = localStorage.getItem("username");
            this.setState({
                username: username
            })
        }
    
        render() {
            return (
                
    goodbye {this.state.username}
    ) } } export default Goodbye;

    我們可以通過剛剛高階函數的思想來創建一個中間組件,也就是我們說的高階組件。

    import React, {Component} from "react"
    
    export default (WrappedComponent) => {
        class NewComponent extends Component {
            constructor() {
                super();
                this.state = {
                    username: ""
                }
            }
    
            componentWillMount() {
                let username = localStorage.getItem("username");
                this.setState({
                    username: username
                })
            }
    
            render() {
                return 
            }
        }
    
        return NewComponent
    }
    import React, {Component} from "react";
    import wrapWithUsername from "wrapWithUsername";
    
    class Welcome extends Component {
    
        render() {
            return (
                
    welcome {this.props.username}
    ) } } Welcome = wrapWithUsername(Welcome); export default Welcome;
    import React, {Component} from "react";
    import wrapWithUsername from "wrapWithUsername";
    
    class Goodbye extends Component {
    
        render() {
            return (
                
    goodbye {this.props.username}
    ) } } Goodbye = wrapWithUsername(Goodbye); export default Goodbye;

    看到沒有,高階組件就是把 username 通過 props 傳遞給目標組件了。目標組件只管從 props里面拿來用就好了。

    為了代碼的復用性,我們應該盡量減少代碼的冗余。

    提取共享的state,如果有兩個組件都需要加載同樣的數據,那么他們會有相同的 componentDidMount 函數。

    找出重復的代碼,每個組件中constructor 和 componentDidMount都干著同樣的事情,另外,在數據拉取時都會顯示Loading... 文案,那么我們應該思考如何使用高階組件來提取這些方法。

    遷移重復的代碼到高階組件

    包裹組件,并且使用props替換state

    盡可能地簡化

    組件開發基本思想 單功能原則

    使用react時,組件或容器的代碼在根本上必須只負責一塊UI功能。

    讓組件保持簡單

    如果組件根本不需要狀態,那么就使用函數定義的無狀態組件。

    從性能上來說,函數定義的無狀態組件 > ES6 class 定義的組件 > 通過 React.createClass() 定義的組件。

    僅傳遞組件所需要的屬性。只有當屬性列表太長時,才使用{...this.props}進行傳遞。

    如果組件里面有太多的判斷邏輯(if-else語句)通常意味著這個組件需要被拆分成更細的組件或模塊。

    使用明確的命名能夠讓開發者明白它的功能,有助于組件復用。

    基本準則

    shouldComponentUpdate中避免不必要的檢查.

    盡量使用不可變數據類型(Immutable).

    編寫針對產品環境的打包配置(Production Build).

    通過Chrome Timeline來記錄組件所耗費的資源.

    componentWillMount或者componentDidMount里面通過setTimeOut或者requestAnimationFram來延遲執行那些需要大量計算的任務.

    組件開發技巧 form表單里的受控組件和不受控組件 受控組件

    在大多數情況下,我們推薦使用受控組件來實現表單。在受控組件中,表單數據由 React 組件負責處理。下面是一個典型的受控組建。

    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {value: ""};
    
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
    
      handleChange(event) {
        this.setState({value: event.target.value});
      }
    
      handleSubmit(event) {
        alert("A name was submitted: " + this.state.value);
        event.preventDefault();
      }
    
      render() {
        return (
          
    ); } }

    設置表單元素的value屬性之后,其顯示值將由this.state.value決定,以滿足React狀態的同一數據理念。每次鍵盤敲擊之后會執行handleChange方法以更新React狀態,顯示值也將隨著用戶的輸入改變。

    對于受控組件來說,每一次 state(狀態)變化都會伴有相關聯的處理函數。這使得可以直接修改或驗證用戶的輸入和提交表單。

    不受控組件

    因為不受控組件的數據來源是 DOM 元素,當使用不受控組件時很容易實現 React 代碼與非 React 代碼的集成。如果你希望的是快速開發、不要求代碼質量,不受控組件可以一定程度上減少代碼量。否則。你應該使用受控組件。

    一般情況下不受控組件我們使用ref來獲取DOM元素進行操作。

    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
    
      handleSubmit(event) {
        alert("A name was submitted: " + this.input.value);
        event.preventDefault();
      }
    
      render() {
        return (
          
    ); } }
    組件條件判斷 三元函數組件判斷渲染
    const sampleComponent = () => {
      return isTrue ? 

    True!

    :

    false!

    };
    使用&&表達式替換不必要的三元函數
    const sampleComponent = () => {
      return isTrue ? 

    True!

    : };
    const sampleComponent = () => {
      return isTrue && 

    True!

    };

    需要注意的是如果isTrue 為 0 ,其實會轉換成 false,但是在頁面中顯示的時候,&&還是會返回0顯示到頁面中。

    多重嵌套判斷
    // 問題代碼
    const sampleComponent = () => {
      return (
        
    {flag && flag2 && !flag3 ? flag4 ?

    Blah

    : flag5 ?

    Meh

    :

    Herp

    :

    Derp

    }
    ) };

    解決方案:

    最佳方案: 將邏輯移到子組件內部

    使用IIFE(Immediately-Invoked Function Expression 立即執行函數)

    滿足條件的時候使用return強制跳出函數

    const sampleComponent = () => {
      const basicCondition = flag && flag2 && !flag3;
      if (!basicCondition) return 

    Derp

    ; if (flag4) return

    Blah

    ; if (flag5) return

    Meh

    ; return

    Herp

    }
    setState異步性

    在某些情況下,React框架出于性能優化考慮,可能會將多次state更新合并成一次更新。正因為如此,setState實際上是一個異步的函數。 如果在調用setState()函數之后嘗試去訪問this.state,你得到的可能還是setState()函數執行之前的結果。

    但是,有一些行為也會阻止React框架本身對于多次state更新的合并,從而讓state的更新變得同步化。 比如: eventListeners, Ajax, setTimeout 等等。

    React框架之所以在選擇在調用setState函數之后立即更新state而不是采用框架默認的方式,即合并多次state更新為一次更新,是因為這些函數調用(fetch,setTimeout等瀏覽器層面的API調用)并不處于React框架的上下文中,React沒有辦法對其進行控制。React在此時采用的策略就是及時更新,確保在這些函數執行之后的其他代碼能拿到正確的數據(即更新過的state)。

    解決setState函數異步的辦法?

    根據React官方文檔,setState函數實際上接收兩個參數,其中第二個參數類型是一個函數,作為setState函數執行后的回調。通過傳入回調函數的方式,React可以保證傳入的回調函數一定是在setState成功更新this.state之后再執行。

    this.setState({count: 1}, () => {
        console.log(this.state.count); // 1
    })
    React源碼中setState的實現
    ReactComponent.prototype.setState = function(partialState, callback) {
      invariant(
        typeof partialState === "object" ||
        typeof partialState === "function" ||
        partialState == null,
        "setState(...): takes an object of state variables to update or a " +
        "function which returns an object of state variables."
      );
      this.updater.enqueueSetState(this, partialState);
      if (callback) {
        this.updater.enqueueCallback(this, callback, "setState");
      }
    };

    updater的這兩個方法,和React底層的Virtual Dom(虛擬DOM樹)的diff算法有緊密的關系,所以真正決定同步還是異步的其實是Virtual DOMdiff算法。

    依賴注入

    React中,想做依賴注入(Dependency Injection)其實相當簡單。可以通過props來進行傳遞。但是,如果組件數量很多,并且組件嵌套層次很深的話,這種方式就不太合適。

    高階組件
    // inject.jsx
    var title = "React Dependency Injection";
    export default function inject(Component) {
      return class Injector extends React.Component {
        render() {
          return (
            
          )
        }
      };
    }
    // Title.jsx
    export default function Title(props) {
      return 

    { props.title }

    ; }
    // Header.jsx
    import inject from "./inject.jsx";
    import Title from "./Title.jsx";
    
    var EnhancedTitle = inject(Title);
    export default function Header() {
      return (
        
    ); }
    context

    React v16.3.0 之前的 Context:

    var context = { title: "React in patterns" };
    class App extends React.Component {
      getChildContext() {
        return context;
      }
      // ...
    }
    
    App.childContextTypes = {
      title: PropTypes.string
    };
    class Inject extends React.Component {
      render() {
        var title = this.context.title;
      // ...
      }
    }
    Inject.contextTypes = {
      title: PropTypes.string
    };

    之前的 Context 作為一個實驗性質的 API,直到 React v16.3.0 版本前都一直不被官方所提倡去使用,其主要原因就是因為在子組件中使用 Context 會破壞 React 應用的分型架構。

    這里的分形架構指的是從理想的 React 應用的根組件樹中抽取的任意一部分都仍是一個可以直接運行的子組件樹。在這個子組件樹之上再包一層,就可以將它無縫地移植到任意一個其他的根組件樹中。

    但如果根組件樹中有任意一個組件使用了支持透傳的 Context API,那么如果把包含了這個組件的子組件樹多帶帶拿出來,因為缺少了提供 Context 值的根組件樹,這時的這個子組件樹是無法直接運行的。

    并且他有一個致命缺陷:任何一個中間傳遞的組件shouldComponentUpdate 函數返回false,組件都不會得到更新。

    新的Context Api

    新的Context Api 采用聲明式的寫法,并且可以透過shouldComponentUpdate 函數返回false的組件繼續向下傳播,以保證目標組件一定可以接收到頂層組件 Context 值的更新,一舉解決了現有 Context API 的兩大弊端,也終于成為了 React 中的第一級(first-class) API

    新的 Context API 分為三個組成部分:

    React.createContext 用于初始化一個 Context

    XXXContext.Provider作為頂層組件接收一個名為 valueprop,可以接收任意需要被放入 Context 中的字符串,數字,甚至是函數。

    XXXContext.Consumer作為目標組件可以出現在組件樹的任意位置(在 Provider 之后),接收 children prop,這里的 children 必須是一個函數(context => ())用來接收從頂層傳來的 Context

    const ThemeContext = React.createContext("light");
    
    class App extends React.Component {
      render() {
        return (
          
            
          
        );
      }
    }
    
    function Toolbar(props) {
      return (
        
    ); } function ThemedButton(props) { return ( {theme =>
    事件處理中的this指向問題
    class Switcher extends React.Component {
      constructor(props) {
        super(props);
        this.state = { name: "React in patterns" };
      }
      render() {
        return (
          
        );
      }
    
      _handleButtonClick() {
        console.log(`Button is clicked inside ${ this.state.name }`);
        // 將導致
        // Uncaught TypeError: Cannot read property "state" of null
      }
    }

    我們可以通過下面三種方式簡單實現this指向的綁定:

    constructor 中事先綁定 this._buttonClick = this._handleButtonClick.bind(this);

    調用時使用箭頭函數

    文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

    轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95244.html

    相關文章

    • 前端每周清單:Node.js 微服務實踐,Vue.js 與 GraphQL,Angular 組件技巧

      摘要:前端每周清單第期微服務實踐,與,組件技巧,攻防作者王下邀月熊編輯徐川前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。 前端每周清單第 26 期:Node.js 微服務實踐,Vue.js 與 GraphQL,Angular 組件技巧,HeadlessChrome 攻防 作者:王下邀月熊 編輯:徐川...

      wall2flower 評論0 收藏0
    • 精讀《源碼學習》

      摘要:精讀原文介紹了學習源碼的兩個技巧,并利用實例說明了源碼學習過程中可以學到許多周邊知識,都讓我們受益匪淺。討論地址是精讀源碼學習如果你想參與討論,請點擊這里,每周都有新的主題,周末或周一發布。 1. 引言 javascript-knowledge-reading-source-code 這篇文章介紹了閱讀源碼的重要性,精讀系列也已有八期源碼系列文章,分別是: 精讀《Immer.js》源...

      aboutU 評論0 收藏0
    • Vue.js 的注意事項與技巧

      摘要:需要注意的是,同樣的行為也適用于。這意味著我們必須重新綁定每個事件。組件的由調用它的父組件提供,這意味著所有事件都應該與父組件相關聯。 原文鏈接:Vue.js — Considerations and Tricks showImg(https://segmentfault.com/img/bVbqHOd?w=1600&h=1599); Vue.js 是一個很棒的框架。然而,當你開始構建...

      lsxiao 評論0 收藏0
    • 前端資源系列(4)-前端學習資源分享&前端面試資源匯總

      摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...

      princekin 評論0 收藏0

    發表評論

    0條評論

    最新活動
    閱讀需要支付1元查看
    <