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属性值。除了标准的属性名之外,我们还会用到如下两个设置:
propTypes:用于定义Props的类型,这有助于追踪运行时误设置的Prop值。
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
版权声明
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!