天天看點

React的元件模式

摘要: 元件是 React 的核心。

Fundebug

經授權轉載,版權歸原作者所有。

React的元件模式

元件是 React 的核心,是以了解如何利用它們對于建立優秀的設計結構至關重要。

什麼是元件

根據 React 官網的介紹,“元件讓你可以将 UI 分割成獨立的、可重用的部分,并獨立管理每個部分。”

當你第一次安裝

npm install react

時,會得到一件事:元件及其 API。與 JavaScript 函數類似,元件接受名為 “props” 的輸入并傳回 React 元素,該元素描述(聲明)使用者界面(UI)的外觀。這就是為什麼 React 被稱為聲明性 API,因為你告訴它你希望 UI 是什麼樣子的,而 React 負責其餘的工作。

可以把聲明式想像成當打的去一個目的地時,隻需要告訴司機去哪裡,他就會開車把你送到那裡。指令式程式設計正好相反—,你得自己駕車到那裡。

元件的 API

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

React的元件模式
  • render
  • state
  • props
  • context
  • lifecycle events

盡管一個元件可以使用上述所有 API,但一個元件通常用到隻有少數幾個 API,而其他元件則隻使用其他 API。

可以對元件使用不同的 API 對元件進行劃分,分為 有狀态(stateful) 和 無狀态(stateless) 兩種元件。

  • 有狀态元件通常使用 API: render, state 和生命周期相關事件。
  • 無狀态元件通常使用 API: render, props 和 context。
React的元件模式

以上就是我們為佬要介紹 元件模式 的原因。元件模式是使用 React 時的最佳實踐,最初引入元件模式是為了将資料邏輯和 UI 表現層進行分離。通過在元件之間劃分職責,您以建立更多可重用的、内聚的元件,這些元件可用于組合複雜的 UI,這在建構可擴充的應用程式時尤其重要。

元件模式

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

  • Container (容器元件)
  • Presentational (展示元件)
  • Higher order components (進階元件)
  • Render callback (渲染回調)

代碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 調試,這邊順便給大家推薦一個好用的BUG監控工具

“容器元件就是取資料,然後渲染子元件而已” —— Jason Bonta

React的元件模式

容器元件是你的資料或邏輯層并利用 stateful API,使用生命周期事件,你可以連接配接

state

redux

或者

Flux

storage

中,并将資料和回調作為

props

傳遞給子元件。

在容器元件的

render

方法中,你可以使用 展示元件 來渲染具體的樣式。為了能夠通路到所有狀态 API,容器元件必須使用

class

的方式聲明,而不是使用函數式方法聲明。

在下面的示例中,我們有一個名為

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

成為一個容器元件,我們可以将 UI 拆分為一個 展示元件,将在下面進行說明。

展示元件

展示元件 使用

props

render

context

(無狀态API),并且由于不需要使用生命周期相關 Api,可以使用純函數來簡化表述它們:

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

展示元件 僅從

props

接收資料和回調,這些資料和回調可以由其容器元件(父元件)提供。

React的元件模式

容器元件和展示元件各自将資料/邏輯和展示部分封裝到各自的元件中:

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>
    );
  }
}           

如你所見,已經将

Greeting

元件中展示相關的部分移動到了它自己的函數式展示元件中。當然,這是一個非常簡單的例子——對于更複雜的應用程式,這也是最基本的。

高階元件

高階元件是一種函數,它接受一個元件作為參數,然後傳回一個新的元件。

這是一種可以對輸入元件的

props

進行修改(增删改查)然後傳回全新的修改後的元件強大模式,想想 react-router-v4 和 redux 。用了 react-router-v4 後,你可以使用 withRouter() 來繼承以

props

形式傳遞給元件的各種方法。同樣,用了

redux

,就可以使用

connect({})()

方法來将展示元件和

store

中的資料進行連接配接。

React的元件模式

代碼示範:

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()

方法封裝它。 在 元件 App 的生命周期事件

componentDidMount()

方法中,我們使用

this.props.location.pathname

提供的值來更新

state

。 由于我們使用了

withRouter

高階元件,我們可以直接通路

this.props.locationlocation

,而不需要直接将

location

作為

props

直接傳入,非常友善。

渲染回調

與高階元件類似,渲染回調或渲染

props

被用于共享或重用元件邏輯。雖然許多開發人員傾向于使用 高階元件 的可重用邏輯,但是使用 渲染回調 仍然有一些非常好的理由和優勢——這是在 Michael Jackson 的

“永不寫另一個高階元件”

中得到了最好的解釋。簡而言之,渲染回調減少了命名空間沖突,并更好的說明了邏輯來源。

React的元件模式
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.children

并将

this.state

作為參數。在

App

類中,我們可以将我們元件封裝在

Counter

元件中,是以我可以操作

Counter

元件内的邏輯。

Counter

元件的本質是暴露了

children

這個外部屬性,将

children

具體的渲染細節交個

Counter

的使用者,使用的時候隻需要将元件傳入到

Counter

children

中,當然可以使用其他參數,如果

children

不夠的話。

React component patterns

關于Fundebug

專注于JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟體、百姓網等衆多品牌企業。歡迎大家

免費試用

繼續閱讀