(譯)React 組件設計模式基礎

原文連接:React Component Patternsjavascript

做者:Gustavo Matheus前端

隨着 React 在前端開發中愈來愈流行,各類各樣的設計模式及新概念亦層出不窮。本文旨在總結 React 開發中一些常見的設計模式。java

有狀態 (Stateful) vs 無狀態 (stateless)

React 組件能夠是有狀態的,在其生命週期內能夠操縱並改變其內部狀態;React 組件也能夠是無狀態的,它僅接受來自父組件傳入的 props,並進行展現。react

下面是一個無狀態Button 組件,它的行爲徹底由傳入的 props 決定:git

const Button = props => 
  <button onClick={props.onClick}>
    {props.text}
  </button>
複製代碼

下面是一個有狀態組件(使用了上述的無狀態組件):github

class ButtonCounter extends React.Component {
  constructor() {
    super();
    this.state = { clicks: 0 };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({ clicks: ++this.state.clicks });
  }

  render() {
    return (
      <Button onClick={this.handleClick} text={`You've clicked me ${this.state.clicks} times !`} /> ) } } 複製代碼

正如你所看到的,上述 ButtonCounter 組件在 state 中維護了本身的狀態,而以前的 Button 組件僅根據 props 來進行渲染展現。這個區別看似很小,可是無狀態的 Button 組件卻高度可複用。設計模式

容器(Container) vs 展現(Presentational) 組件

當與外部數據進行交互時,咱們能夠把組件分爲兩類:微信

  • 容器組件:主要負責同外部數據進行交互(通訊),譬如與 Redux 等進行數據綁定等。
  • 展現組件:根據自身 state 及接收自父組件的 props 作渲染,並不直接與外部數據源進行溝通。

咱們來看一個展現組件:less

const UserList = props =>
  <ul>
    {props.users.map(u => (
      <li>{u.name} - {u.age} years old</li>
    ))}
  </ul>
複製代碼

而這個展現組件能夠被一個容器組件更新:函數

class UserListContainer extends React.Component {
  constructor() {
    super()
    this.state = { users: [] }
  }

  componentDidMount() {
    fetchUsers(users => this.setState({ users }));
  }

  render() {
    return <UserList users={this.state.users} /> } } 複製代碼

經過將組件區分爲容器組件與展現組件,將數據獲取與渲染進行分離。這也使 UserList 可複用。若是你想了解更多,這裏有一些很是好的文章,解釋地很是清楚。

高階(Higher-Order)組件

當你想複用一個組件的邏輯時,高階組件(HOC)就派上用場了。高階組件就是 JavaScript 函數,接收 React 組件做爲參數,並返回一個新組件。

舉個例子:編寫一個菜單組件,當點擊一個菜單項時,展開當前菜單項,顯示子菜單。固然咱們能夠在父組件裏來控制此菜單組件的狀態,可是更優雅的方式,是使用高階組件:

function makeToggleable(Clickable) {
  return class extends React.Component {
    constructor() {
      super();
      this.toggle = this.toggle.bind(this);
      this.state = { show: false };
    }

    toggle() {
      this.setState({ show: !this.state.show });
    }

    render() {
      return (
        <div> <Clickable {...this.props} onClick={this.toggle} /> {this.state.show && this.props.children} </div> ); } } } 複製代碼

經過這種方式,咱們可使用 JavaScript 的裝飾器語法,將咱們的邏輯應用於 ToggleableMenu 組件:

@makeToggleable
class ToggleableMenu extends React.Component {
  render() {
    return (
      <div onClick={this.props.onClick}> <h1>{this.props.title}</h1> </div>
    );
  }
}
複製代碼

如今,咱們能夠將任何子菜單內容放入 ToggleableMenu 組件中:

class Menu extends React.Component {
  render() {
    return (
      <div> <ToggleableMenu title="First Menu"> <p>Some content</p> </ToggleableMenu> <ToggleableMenu title="Second Menu"> <p>Another content</p> </ToggleableMenu> <ToggleableMenu title="Third Menu"> <p>More content</p> </ToggleableMenu> </div>
    );
  }
}
複製代碼

當你在使用 Reduxconnect,或者 React RouterwithRouter 函數時,你就是在使用高階組件!

渲染回調(Render Callbacks)

除了上述的高階組件外,渲染回調是另外一種使組件可複用的設計模式。渲染回調的核心是組件接收的子組件(或子結點,亦即 props.children),不以 React Component 提供,而是以回調函數的形式提供。以上述 HOC 組件爲例,咱們經過渲染回調的方式重寫以下:

class Toggleable extends React.Component {
  constructor() {
    super();
    this.toggle = this.toggle.bind(this);
    this.state = { show: false }
  }

  toggle() {
    this.setState({ show: !this.state.show });
  }

  render() {
    return this.props.children(this.state.show, this.toggle)
  }
}
複製代碼

如今,咱們能夠傳入回調函數給 Toggleable 組件做爲子結點。 咱們用新方式實現以前的 HOC 組件 ToggleableMenu

const ToggleableMenu = props => (
  <Toggleable> {(show, onClick) => ( <div> <div onClick={onClick}> <h1>{props.title}</h1> </div> { show && props.children } </div> )} </Toggleable>
)
複製代碼

而咱們全新的 Menu 組件實現以下:

class Menu extends React.Component {
  render() {
    return (
      <div> <ToggleableMenu title="First Menu"> <p>Some content</p> </ToggleableMenu> <ToggleableMenu title="Second Menu"> <p>Another content</p> </ToggleableMenu> <ToggleableMenu title="Third Menu"> <p>More content</p> </ToggleableMenu> </div>
    );
  }
}
複製代碼

是的,你沒有看錯,新的 Menu 組件同以前以HOC模式實現出來的如出一轍!

在這種實現方式下,咱們將組件內部的狀態(state)與組件的渲染邏輯進行剝離。在上面的例子中,咱們將渲染邏輯放在了 ToggleableMenu渲染回調中,而展現組件的狀態(state)依然在 Toggleable 組件內進行維護。

瞭解更多

以上的一些例子僅僅是 React 設計模式的基礎知識。若是你想更加深刻地瞭解關於 React 設計模式的話題,如下是一些很是好的學習資料,值得一看:


關注微信公衆號:創宇前端(KnownsecFED),碼上獲取更多優質乾貨!

相關文章
相關標籤/搜索