React设计模式:深入理解React&Redu原理套路

原文地址

本文从属于笔者的React入门与最佳实践系列,推荐阅读GUI应用程序架构的十年变迁:MVC,MVP,MVVM,Unidirectional,Clean

Communication

React组件一个很大的特性在于其拥有自己完整的生命周期,因此我们可以将React组件视作可自运行的小型系统,它拥有自己的内部状态、输入与输出。

Input

对于React组件而言,其输入的来源就是Props,我们会用如下方式向某个React组件传入数据:

// Title.jsxclass Title extends React.Component {  render() {    return # { this.props.text };  }};Title.propTypes = {  text: React.PropTypes.string};Title.defaultProps = {  text: 'Hello world'};// App.jsxclass App extends React.Component {  render() {    return ;  }};

text是Text组件自己的输入域,父组件App在使用子组件Title时候应该提供text属性值。除了标准的属性名之外,我们还会用到如下两个设置:

  1. propTypes:用于定义Props的类型,这有助于追踪运行时误设置的Prop值。

  2. defaultProps:定义Props的默认值,这个在开发时很有帮助

Props中还有一个特殊的属性props.children可以允许我们使用子组件:

class Title extends React.Component {  render() {    return (      #         { this.props.text }        { this.props.children }    );  }};class App extends React.Component {  render() {    return (        community    );  }};

注意,如果我们不主动在Title组件的render函数中设置{this.props.children},那么span标签是不会被渲染出来的。除了Props之外,另一个隐性的组件的输入即是context,整个React组件树会拥有一个context对象,它可以被树中挂载的每个组件所访问到,关于此部分更多的内容请参考依赖注入这一章节。

Output

组件最明显的输出就是渲染后的HTML文本,即是React组件渲染结果的可视化展示。当然,部分包含了逻辑的组件也可能发送或者触发某些Action或者Event。

class Title extends React.Component {  render() {    return (      # ![超级产品经理](https://v1cdn.imspm.com/imspm.com超级产品经理2016080123bkrifd35sgq.jpg);    }  });  return Wrapper;};

其中Component代指我们需要附着到Store中的View,而consumer则是应该被传递给View的Store中的部分的状态,简单的用法为:

class MyView extends React.Component {  ...}ProfilePage = connectToStores(MyView, store, (props, store) => ({  data: store.get('key')}));

这种模式的优势在于其有效地分割了各个模块间的职责,在该模式中Store并不需要主动地推送消息给View,而主需要简单地修改数据然后广播说我的状态已经更新了,然后由HOC去主动地抓取数据。那么在作者具体的实现中,就是选用了HOC模式:

register: function (store) {  if (!store || !store.update) {    throw new Error('You should provide a store that has an `update` method.');  } else {    var consumers = [];    var change = function () {      consumers.forEach(function (l) {        l(store);      });    };    var subscribe = function (consumer) {      consumers.push(consumer);    };    this._stores.push({ store: store, change: change });    return subscribe;  }  return false;},dispatch: function (action) {  if (this._stores.length > 0) {    this._stores.forEach(function (entry) {      entry.store.update(action, entry.change);    });  }}

另一个常见的用户场景就是我们需要为界面提供一些默认的状态,换言之当每个consumer注册的时候需要提供一些初始化的默认数据:

var subscribe = function (consumer, noInit) {  consumers.push(consumer);  !noInit ? consumer(store) : null;};

综上所述,最终的Dispatcher函数如下所示:

var Dispatcher = function () {  return {    _stores: [],    register: function (store) {      if (!store || !store.update) {        throw new Error('You should provide a store that has an `update` method.');      } else {        var consumers = [];        var change = function () {          consumers.forEach(function (l) {            l(store);          });        };        var subscribe = function (consumer, noInit) {          consumers.push(consumer);          !noInit ? consumer(store) : null;        };        this._stores.push({ store: store, change: change });        return subscribe;      }      return false;    },    dispatch: function (action) {      if (this._stores.length > 0) {        this._stores.forEach(function (entry) {          entry.store.update(action, entry.change);        });      }    }  }};

Actions

Actions就是在系统中各个模块之间传递的消息载体,作者觉得应该使用标准的Flux Action模式:

{  type: 'USER_LOGIN_REQUEST',  payload: {    username: '...',    password: '...'  }}

其中的type属性表明该Action所代表的操作而payload中包含了相关的数据。另外,在某些情况下Action中没有带有Payload,因此可以使用Partial Application方式来创建标准的Action请求:

var createAction = function (type) {  if (!type) {    throw new Error('Please, provide action\'s type.');  } else {    return function (payload) {      return dispatcher.dispatch({ type: type, payload: payload });    }  }}

Final Code

上文我们已经了解了核心的Dispatcher与Action的构造过程,那么在这里我们将这二者组合起来:

var createSubscriber = function (store) {  return dispatcher.register(store);}

并且为了不直接暴露dispatcher对象,我们可以允许用户使用createAction与createSubscriber这两个函数:

var Dispatcher = function () {  return {    _stores: [],    register: function (store) {      if (!store || !store.update) {        throw new Error('You should provide a store that has an `update` method.');      } else {        var consumers = [];        var change = function () {          consumers.forEach(function (l) {            l(store);          });        };        var subscribe = function (consumer, noInit) {          consumers.push(consumer);          !noInit ? consumer(store) : null;        };        this._stores.push({ store: store, change: change });        return subscribe;      }      return false;    },    dispatch: function (action) {      if (this._stores.length > 0) {        this._stores.forEach(function (entry) {          entry.store.update(action, entry.change);        });      }    }  }};module.exports = {  create: function () {    var dispatcher = Dispatcher();    return {      createAction: function (type) {        if (!type) {          throw new Error('Please, provide action\'s type.');        } else {          return function (payload) {            return dispatcher.dispatch({ type: type, payload: payload });          }        }      },      createSubscriber: function (store) {        return dispatcher.register(store);      }    }  }};

关键字:react.js, Redux

版权声明

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部