over 3 years ago

由於 ES6 的 React.Component 方式不支援 Mixins 語法
為啥不採用 Mixins 請查看 Mixins Are Dead. Long Live Composition
並建議採用 Higher order component 組合的方式來實現 Mixins 功能

何謂 Higher order component (HOC)

其實就是一個函數
接收某個現有的 Component
並 return 一個 class extends React.Component
且在內部 render() return 接收的 Component

範例如下

const HOC = (Component) => class extends React.Component {
  constructor(props) {
    super(props);
  }
  // do whatever you may want
  render() {
    // pass new properties to wrapped component
    return <Component {...this.props} {...this.state} />
  }
};

因此可以將一些固定的邏輯放至 Higher order component 中
來變動 props 及 state 傳遞給接收的 Component

實作範例

建立 Hoc\HOC.js

import React from 'react';

const HOC = (Component, state, intervalFn) => class extends React.Component {
  constructor(props) {
    super(props);
    this.state = state;
  }

  componentWillMount() {
    this.intervals = [];
  }

  componentWillUnmount() {
    // Unmount 時清除所有 clearInterval
    this.intervals.forEach(clearInterval);
  }

  componentDidMount() {
   // DidMount時執行 setInterval 觸發 tick()
    this.setInterval(this.tick.bind(this), 1000);
  }

  setInterval() {
    // 堆疊 setInterval
    this.intervals.push(setInterval.apply(null, arguments));
  }

  tick() {
    // 觸發變動 state 函數 intervalFn
    this.setState(intervalFn(this.state));
  }

  render() {
    // 配置 props 及 state
    return <Component {...this.props} {...this.state} />
  }
};

export default HOC

建立 Component\TickTock.js

import React from 'react';

class TickTock extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <p>
          React has been running for {this.props.seconds} seconds.
        </p>
    );
  }
}

TickTock.propTypes = {
  seconds: React.PropTypes.number.isRequired,
}

export default TickTock

建立 main.js

import React from 'react';
import ReactDOM from 'react-dom';
import HOC from './Hoc/HOC';
import TickTock from './Component/TickTock';

const intervalFn = (state) => {
  return {seconds: state.seconds + 1};
};

const Wrapped = HOC(TickTock, { seconds: 0 }, intervalFn);
const Wrapped2 = HOC(TickTock, { seconds: 3 }, intervalFn);
const Wrapped3 = HOC(TickTock, { seconds: 6 }, intervalFn);

ReactDOM.render(
  <div>
    <Wrapped />
    <Wrapped2 />
    <Wrapped3 />
  </div>,
  document.getElementById('demo')
);

利用 HOC 傳入 TickTock 及 預設的 state 狀態和做加總的 intervalFn 函數
模擬 Mixins 實現擴充 TickTock 內的功能
由於每次呼叫都會執行 return class extends React.Component
所以能避免 Component 重複使用 Mixins 的陷阱

執行效果

componentWillMount 與 componentDidMount 的先後順序

來源網址
http://www.darul.io/post/2016-01-05_react-higher-order-components

← React 使用 babel-plugin-transform-react-inline-elements 優化 runtime performance Webpack 啟用 Source Map 功能 →
 
comments powered by Disqus