React 組件模式


簡評:組件(component)是 React 的核心,了解它們有助於構建好的設計結構。

什么是組件(component)

組件運行你將 UI 拆分為獨立的可重用的部分。和 JavaScript 函數類似,組件接收名為 props 的輸入並返回 React 元素,它描述(聲明)用戶界面應該是什么樣子的。這就是 React 被稱為聲明性 API 的原因,你只需要聲明你希望得到的 UI ,之后 React 負責具體的細節。

組件 API

當安裝 React 后,便可以使用 React 提供的 API,基本可以分成 5 種。

  • render
  • state
  • props
  • context
  • lifecycle events

雖然組件可以使用所有的 API,但是通常一個組件只使用部分的 API,我們可以對使用不同 API 的組件進行細分,分成有狀態(stateful) 和無狀態(stateless) 兩種組件。

  • 有狀態組件使用(render,state 和 生命周期相關事件)
  • 無狀態組件使用 (render,props 和 context)

這樣將數據邏輯和 UI 表現層進行分離,通過組件之間划分職責可以創建更多可重用的組件,在構建可擴展的應用程序時尤為重要。

組件模式

通常組件模式有以下幾種:

  • Container
  • Presentational
  • 高階組件(Higher order components 【HOC’s】)
  • Render callback

container

容器組件(container component )負責獲取數據然后渲染部分交給相應的子組件來負責。

容器是你的數據或邏輯層並利用 stateful API,使用生命周期事件你可以連接 state 到 redux 或 flux 的 storage 中。在容器組件的 render 方法中,你可以使用 Presentational 組件來渲染具體的樣式。

注意:由於容器組件需要使用 stateful api ,所以容器組件需要定義成類而不能是一個純函數。

我們來定義一個 組件 Greeting,他具有狀態,生命周期 componentDidMount 事件 和 render 方法。

class Greeting extends React.Component {
  constructor() {
    super();
    this.state = {
      name: "",
    };
  }

  componentDidMount() {
    // AJAX
    this.setState(() => {
      return {
        name: "William",
      };
    });
  }

  render() {
    return (
      <div>
        <h1>Hello! {this.state.name}</h1>
      </div>
    );
  }
}

現在我們對 Greeting 進行改進,將其分離成容器組件(container component)和展示組件(presentational component)。

Presentational

Presentational components 使用 props,render,和 context (stateless API's) ,並且由於不需要使用生命周期相關api,我們可以使用純函數來簡化表述它們:

const GreetingCard = (props) => {
  return (
    <div>
      <h1>Hello! {props.name}</h1>
    </div>
  )
}

Presentational components 只從 props 獲取數據和回調函數,props 由容器組件提供。

容器組件和展示組件各自將數據/邏輯和展示部分封裝到各自的組件中:

const GreetingCard = (props) => {
  return (
    <div>
      <h1>{props.name}</h1>
    </div>
  )
}

class Greeting extends React.Component {
  constructor() {
    super();
    this.state = {
      name: "",
    };
  }

  componentDidMount() {
    // AJAX
    this.setState(() => {
      return {
        name: "William",
      };
    });
  }

  render() {
    return (
      <div>
       <GreetingCard name={this.state.name} />
      </div>
    );
  }
}

高階組件(Higher order components【HOC’s】)

高階組件是一個接收一個組件作為參數然后返回全新組件的函數。

這是一種強大的模式,我們可以對輸入組件的 props 進行修改(增刪改查)然后返回全新的修改后的組件,例如 react-router-v4 的 withRouter() 方法可以包裝任何自定義組件,將 react-router 的 history,location,match 三個對象傳入,不需要一級級傳入。例如 Redux,你可以使用 connect({})() 方法來將展示組件和 store 中的數據進行連接。

代碼演示:

import {withRouter} from 'react-router-dom';

class App extends React.Component {
  constructor() {
    super();
    this.state = {path: ''}
  }
  
  componentDidMount() {
    let pathName = this.props.location.pathname;
    this.setState(() => {
      return {
        path: pathName,
      }
    })
  }
  
  render() {
    return (
      <div>
        <h1>Hi! I'm being rendered at: {this.state.path}</h1>
      </div>
    )
  }
}

export default withRouter(App);

導出組件時,我使用 react-router-v4 的 withRouter() 來封裝它。在 componentDidMount 這個生命周期中,我們使用 this.props.location.pathname 來更新我們的 state,由於我們使用了 withRouter 高階組件,我們可以直接訪問 this.props.locationlocation,而不需要直接將 location 作為 props 直接傳入,非常方便。

Render callbacks

與高階組件類似,render callbacks 或 render props 可以用來重用邏輯。

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  increment = () => {
    this.setState(prevState => {
      return {
        count: prevState.count + 1,
      };
    });
  };

  render() {
    return (
      <div onClick={this.increment}>{this.props.children(this.state)}</div>
    );
  }
}

class App extends React.Component {
  render() {
    return (
      <Counter>
        {state => (
          <div>
            <h1>The count is: {state.count}</h1>
          </div>
        )}
      </Counter>
    );
  }
}

在 Counter 類中,我們 render 中嵌入 this.props.childrn 並將 this.state 作為參數。在 App 類下面,我們可以將我們組件包裝在 Counter 組件中。

Counter 組件的本質是暴露了 children 這個外部屬性,將 children 具體的渲染細節交個 Counter 的使用者,使用的時候只需要將組件傳入到 Counter 的 children 中,當然可以使用其他參數,如果 children 不夠的話。例如實現一個聊天列表每條消息有頭像和消息內容,具體頭像是圓是方,具體消息內容是文字是圖片,都交給了外部使用者。

原文:React component patterns


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM