文章出處

前言

眾所周知,React跟Flux是一對好基友。
其中,市場流行的Flux有Redux,Mobx,Reflux。
其中,用法最簡單的是Reflux。
其數據流思路如下:

+---------+       +--------+       +-----------------+
¦ Actions ¦------>¦ Stores ¦------>¦ View Components ¦
+---------+       +--------+       +-----------------+
     ^                                      ¦
     +--------------------------------------+

我們能否再減少其數據流路徑?如下:

 +--------+       +-----------------+
 ¦ Stores ¦------>¦ View Components ¦
 +--------+       +-----------------+
     ^                     ¦
     ----------------------+

兩個字,可以。

需求分析

  1. 集成Actions的功能到Stores。從而拿掉單獨的Actions。
  2. 集成組件的State和Store在一起。
  3. 跨組件通信依賴其Store。

擼函數

這意味著我們的createStore是一個工廠函數。
用來生產每一個React組件實例對應的Store實例。

function isObject(obj) {
  return Object.prototype.toString.call(obj) == '[object Object]';
}

function extend(obj) {
  if (!isObject(obj)) {
    return obj;
  }
  for (let i = 1, length = arguments.length; i < length; i++) {
    let source = arguments[i];

    for (let prop in source) {
      if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
        let propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop);
        Object.defineProperty(obj, prop, propertyDescriptor);
      } else {
        obj[prop] = source[prop];
      }
    }
  }
  return obj;
}

function createStore(definition={}) {

  function Store() {
    let t = this;
    t.data = null;
    extend(t, definition);
    t.trigger = function () {
      this.setState({});
    }

  }
  let store = new Store();
  return store;
};

isObjectextend這兩個函數按下不表。
其中,extend函數是用來對象合并,該函數某部位依賴isObject。((*^__^*) 嘻嘻……)
createStore函數產出的實例內部

  1. data作為組件實例的store。
  2. trigger作為更新組件實例的方法。

萬事具備,只欠東風。

接下來就是用connect函數把組件實例和Store實例連接在一起。

function connect(listenable, context) {
  if(!isObject(listenable)){
    throw new Error('connect function\'s argument is not a object');
  }
  return {
    componentDidMount() {
      context = context || this;
      listenable.trigger = listenable.trigger.bind(context);
    },
    componentWillUnmount() {
      listenable.trigger = null;
    }
  };
}

借用React組件生命周期,在其componentDidMount階段,
改變Store實例的trigger上下文,使其指向React組件實例,
從而方便trigger調用React組件實例的setState方法。
全套代碼如下:

擼Demo

  • Samflux.js
function isObject(obj) {
  return Object.prototype.toString.call(obj) == '[object Object]';
}

function extend(obj) {
  if (!isObject(obj)) {
    return obj;
  }
  for (let i = 1, length = arguments.length; i < length; i++) {
    let source = arguments[i];

    for (let prop in source) {
      if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
        let propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop);
        Object.defineProperty(obj, prop, propertyDescriptor);
      } else {
        obj[prop] = source[prop];
      }
    }
  }
  return obj;
}

exports.createStore = function (definition={}) {

  function Store() {
    let t = this;
    t.data = null;
    extend(t, definition);
    t.trigger = function () {
      this.setState({});
    }

  }
  let store = new Store();
  return store;
};

exports.connect = function (listenable, context) {
  if(!isObject(listenable)){
    throw new Error('connect function\'s argument is not a object');
  }
  return {
    componentDidMount() {
      context = context || this;
      listenable.trigger = listenable.trigger.bind(context);
    },
    componentWillUnmount() {
      listenable.trigger = null;
    }
  };
}
  • store.js
const Samflux = require('./Samflux.js');
const Store = Samflux.createStore({
  data:'old data',
  onSetData: function(){
    this.data = 'new data';
    this.trigger();
  },
});

module.exports = Store;
  • SamfluxTest.js
const Store = require('./store.js');
const Samflux = require('./Samflux.js');
const reactMixin = require('react-mixin');
const React = window.React;
require('./SamfluxTest.less');

class Test extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
    };
  }
  setData(){
    Store.onSetData();
  }
  render() {
    const me = this;
    return (<div className="SamfluxTest" onClick={me.setData.bind(this)}><span>{Store.data}</span></div>);
  }
}

reactMixin.onClass(Test, Samflux.connect(Store));
module.exports = Test;

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()