React Mixins Are Dead in ES6

背景

Unfortunately, we will not launch any mixin support for ES6 classes in React. That would defeat the purpose of only using idiomatic JavaScript concepts.
There is no standard and universal way to define mixins in JavaScript. In fact, several features to support mixins were dropped from ES6 today. There are a lot of libraries with different semantics. We think that there should be one way of defining mixins that you can use for any JavaScript class. React just making another doesn’t help that effort.javascript

React官網 文檔 v0.13 上咱們能夠看到,mixin 再也不被ES6 所支持,但願以更加通用和標準的javascript 概念去取代它。html

關於Mixins

不少時候,不一樣的組件可能須要使用到一些公共的方法,Minxins 能夠包裝這些公共的方法暴露給外部調用。不少狀況下,咱們會定義一些React生命週期的方法,React 會自動地幫咱們把這些方法合併到component 內,這些方法也將被組件所調用。java

可是,使用Mixins也會致使一些問題,主要有如下幾個緣由。react

  • 組件和Mixins 之間的關係式隱式的,Mixins 的內部實現一般都會依賴組件內定義的方法,但對於Mixins 來講,很難知道該方法被定義在哪一個組件中。git

  • 若是一個組件中使用了多個Mixins,而不一樣Mixins卻定義了相同的方法,這個時候就容易引發衝突。github

  • Mixins 嘗試往你的組件中添加更多的state,然而這並非你想要的。 可參考 Why Flux Component is better than Flux Mixin ide

Higher-Order Components

Higher-Order Components是其中一種替代 Mixins 的其中一種解決方案,如今咱們先來看一個 用 mixins 實現的觸發 Flux Stores更新 State 的例子。函數

javascriptfunction StoreMixin(...stores) {
  var Mixin = {
    getInitialState() {
      return this.getStateFromStores(this.props);
    },
    componentDidMount() {
      stores.forEach(store =>
        store.addChangeListener(this.handleStoresChanged)
      );
      this.setState(this.getStateFromStores(this.props));
    },
    componentWillUnmount() {
      stores.forEach(store =>
        store.removeChangeListener(this.handleStoresChanged)
      );
    },
    handleStoresChanged() {
      if (this.isMounted()) {
        this.setState(this.getStateFromStores(this.props));
      }
    }
  };
  return Mixin;
}

在使用的時候,咱們先把 StoreMixin 添加到mixins列表中,而後在組件中定義 getStateFromStores(props) 方法ui

javascriptvar UserProfilePage = React.createClass({
  mixins: [StoreMixin(UserStore)],
  propTypes: {
    userId: PropTypes.number.isRequired
  },
  getStateFromStores(props) {
    return {
      user: UserStore.get(props.userId);
    }
  }
  render() {
    var { user } = this.state;
    return <div>{user ? user.name : 'Loading'}</div>;
  }

這樣,當UserProfilePage 在渲染的時候就會觸發 StoreMixin 中定義的一些生命週期的方法,監聽Store數據變化。變化以後觸發響應的處理函數。this

什麼是 higher-order component ?

higher-order component 是一個接收一個組件,而後返回包裝了該組件的另一個新組件的函數。

嗯,聽起來有點拗口,咱們來舉個例子看看就明白了。

javascriptfunction connectToStores(Component, stores, getStateFromStores) {
  const StoreConnection = React.createClass({
    getInitialState() {
      return getStateFromStores(this.props);
    },
    componentDidMount() {
      stores.forEach(store =>
        store.addChangeListener(this.handleStoresChanged)
      );
    },
    componentWillUnmount() {
      stores.forEach(store =>
        store.removeChangeListener(this.handleStoresChanged)
      );
    },
    handleStoresChanged() {
      if (this.isMounted()) {
        this.setState(getStateFromStores(this.props));
      }
    },
    render() {
      return <Component {...this.props} {...this.state} />;
    }
  });
  return StoreConnection;
};

connectToStores 看起來有點像mixin ,可是和前面的 StoreMixin 不一樣。 StoreMixin 管理的是組件的內部 state。可是 connectToStores 倒是把(Comment)組件包裝起來,而後把props傳遞給它。這樣,經過一種組件內嵌的良好方式,就把組件的生命週期隔離起來,不存在合併的問題。

推薦

ract-dnd 一個專一於控件拖拽的庫,是基於 higher-order component 而實現。

相關文章
相關標籤/搜索