React-Native傻瓜式学习笔记(三):基于事件发布/订阅的网络请求工具类封装
2017-01-18 16:42
666 查看
最近国内外使用React-Native写APP的公司越来越多了,我们公司也不甘落后,将使用React-Native重写APP这个事提上了日程。然而这个任务落到我头上的时候,我本人作为一个Android菜鸡程序猿当即表示“臣妾做不到啊~”,然而并没有什么卵用。没办法,只好硬着头皮现学现卖。这东西刚出时间并不算长,网上完整的系统的参考文章较少,多数都是零碎的知识点,只好在博客里做个笔记,省得忘了以后再去满大街找。。
这一系列笔记内容均仅代表我个人的观点,不保证都是对的
这样一个简单的事件总线就完成了,需要注意的是,每一个订阅者如果想要接收并处理事件,都要自行实现handleEvent方法,在这个问题上,JS没有Interface这种东西让我浑身蓝瘦。然而作为一个菜鸡,我也不知道有什么更好的办法,暂时就先这样了。。放开这个问题先不管,接下来我们开始封装网络请求工具。
至此,网络请求工具就封装好了,让我们来看看怎么用吧(只列出关键代码):
这一系列笔记内容均仅代表我个人的观点,不保证都是对的
起因
在React-Native中进行网络请求时,我们通常会使用JS中提供的fetch方法,通过一系列Promise语法异步的获取服务器返回的信息。实际上,经过不断的演化,fetch方法已经非常易用且语法逻辑清晰。但在实际开发过程中,我们经常会出现写着写着满屏幕的各种fetch.then.then,简直烦的不行,加上每次请求根据业务需要还要传大量相同的header,几行真正的业务逻辑代码在一大坨重复代码中间瑟瑟发抖。。另外,由于RN基于组件(Component)开发的机制,有的时候会出现我需要在一个组件中进行网络请求,但我需要在另一个或多个组件中处理返回的数据(例如:在搜索框组件中发起搜索请求,在结果组件中展示返回的结果),这个时候使用fetch就非常尴尬。因此,网络请求工具的封装势在必行。作为一个深受OO思想荼毒的Android程序员,我第一时间想起了EventBus。EventBus实现
Android中的EventBus是一个非常经典的基于观察者模式的事件发布/订阅框架,在Android开发中被广泛应用。为了解决我”一处发起请求到处接收响应“的需求,我首先就想到了它。因此立刻开始在RN工程中着手搭建,以下是我的EventBus简单实现://EventBus.js let instance = null; // 单例引用 let eventSubscribers = {}; // 使用一个对象保存订阅者(可以视作一个JAVA中的Map,每个key对应一个事件,每个value对应所有订阅该事件的订阅者组成的数组) export default class EventBus { constructor() { // 单例模式,实际上也可以不用,OO害我! if (!instance) { instance = this; } return instance; } /** * 发送事件的方法,这个方法执行后会通知所有订阅了对应事件的订阅者 * @param event 事件内容 * @param type 事件名称,作为区分每个事件的标记 */ sendEvent = (event, type) => { let subscribers = eventSubscribers[type]; if (subscribers && subscribers.length > 0) { subscribers.forEach((subscriber) => { if (subscriber && subscriber !== null && typeof subscriber.handleEvent == 'function') { // 这里调用了订阅者的handleEvent方法,每一个订阅者都要通过实现这个方法来处理接收到的事件 subscriber.handleEvent(event, type); } }); } } /** * 订阅事件的方法 * @param subscriber 订阅者,即订阅事件的对象 * @param type 订阅的事件名称 */ registerEvent = (subscriber, type) => { let subscribers = eventSubscribers[type]; if (subscribers) { subscribers.push(subscriber); } else { eventSubscribers[< bde5 span class="hljs-keyword">type] = [subscriber]; } } /** * 解除订阅事件的方法 * @param subscriber 订阅者,即订阅事件的对象 * @param type 要解除订阅的事件名称 */ unregisterEvent = (subscriber, type) => { let subscribers = eventSubscribers[type]; if (subscribers) { // 从当前订阅了对应事件的订阅者数组中过滤掉解除订阅的订阅者 eventSubscribers[type] = subscribers.filter((sub) => sub !== subscriber) } } }
这样一个简单的事件总线就完成了,需要注意的是,每一个订阅者如果想要接收并处理事件,都要自行实现handleEvent方法,在这个问题上,JS没有Interface这种东西让我浑身蓝瘦。然而作为一个菜鸡,我也不知道有什么更好的办法,暂时就先这样了。。放开这个问题先不管,接下来我们开始封装网络请求工具。
封装网络请求工具
基于上面写好的EventBus,网络请求的封装思路就很简单了:将复用的header封装,并将服务器返回的数据(或错误信息)作为一个event发布出去。工具本身不用知道是谁接收事件,订阅者也不用管我订阅的事件是谁发送的,气氛一片祥和。以下是简单的实现例子://ApiHelper.js import {Platform} from 'react-native'; import EventBus from './EventBus'; import * as UserUtil from './UserUtil'; import * as AppInfo from '../constants/AppInfo'; /** * GET请求 * @param url url地址,可以直接带参数,也可以通过后面的params对象传进来 * @param eventType 用来指定Event类型,通过注册对应的监听并实现handleEvent方法来处理返回的结果。<br> * 正常情况返回json对象,出错返回错误对象,格式:{errorCode: number, msg: string} * @param params 自定义参数对象,{key1: value1, key2: value2, ....},如果已经在url地址里写了这里就不用传 */ export const get = (url, eventType, params) => { if (params) { let paramsArray = []; //拼接参数 Object.keys(params).forEach(key => paramsArray.push(key + '=' + params[key])) if (url.search(/\?/) === -1) { url += '?' + paramsArray.join('&') } else { url += '&' + paramsArray.join('&') } } if (url) { //fetch请求 fetch(url, { method: 'GET', headers: { // 统一的headers 'deviceType': Platform.OS == 'android' ? 1 : 0, 'appVersion': AppInfo.APP_VERSION, 'token': UserUtil.getToken(), 'uid': UserUtil.getUid(), }, }).then((response) => { if (response.ok) { response.json().then(responseJson => { if (eventType) { new EventBus().sendEvent(responseJson, eventType); } }) } else { let error = { errorCode: response.status, msg: response.statusText }; new EventBus().sendEvent(error, eventType); } }).catch((e) => { let error = { errorCode: -1, msg: '', }; new EventBus().sendEvent(error, eventType); }) } } /** * POST请求 * @param url url地址 * @param eventType 用来指定Event类型,通过注册对应的监听并实现handleEvent方法来处理返回的结果,出错返回错误对象,格式:{errorCode: number, msg: string} * @param params 自定义参数对象,{key1: value1, key2: value2, ....} */ export const post = (url, eventType, params) => { if (url) { let paramsArray = []; if (params) { //拼接参数 Object.keys(params).forEach(key => paramsArray.push(key + '=' + params[key])); bodyStr += paramsArray.join('&') } //fetch请求 fetch(url, { method: 'POST', headers: { // 统一的headers 'deviceType': Platform.OS == 'android' ? 1 : 0, 'appVersion': AppInfo.APP_VERSION, 'token': UserUtil.getToken(), 'uid': UserUtil.getUid(), 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', }, body: bodyStr, }).then((response) => { if (response.ok) { response.json().then(responseJson => { if (eventType) { new EventBus().sendEvent(responseJson, eventType); } }) } else { let error = { errorCode: response.status, msg: response.statusText }; new EventBus().sendEvent(error, eventType); } }).catch((e) => { let error = { errorCode: -1, msg: '', }; new EventBus().sendEvent(error, eventType); }) } }
至此,网络请求工具就封装好了,让我们来看看怎么用吧(只列出关键代码):
//DemoComponent.js //省略一大堆引用... export default class DemoComponent extends Component { ... componentDidMount() { //组件渲染后订阅事件 new EventBus().registerEvent(this, 'demo1'); new EventBus().registerEvent(this, 'demo2'); this.getData(); } componentWillUnmount() { //组件销毁前解除订阅事件 new EventBus().unregisterEvent(this, 'demo1'); new EventBus().unregisterEvent(this, 'demo2'); } //执行网络请求,并指定该请求对应的EventType getData = () => { ApiHelper.get('http://www.example1.com','demo1'); ApiHelper.get('http://www.example2.com','demo2'); } //实现handleEvent方法以接收并处理事件 handleEvent = (event, type) => { switch (type) { case 'demo1': //处理事件... break; case 'demo2': //处理事件... break; } }; ... }
总结
实际上EventBus不止能用来作为网络请求数据传递的工具,同时也可以作为一个非常方便的Component间传递数据的工具,不过再此就不赘述了。总之与网络请求工具配合起来相当的好用,随时随地发请求,想在哪接就在哪接,简直一身轻松。相关文章推荐
- React-Native傻瓜式学习笔记(二):封装Navigator工具类
- React-Native 学习笔记十七(网络请求)
- React Native 学习笔记(九)--网络请求 & 界面跳转
- React-Native学习笔记之:Fetch网络请求
- React-Native傻瓜式学习笔记(一):ListView的简单使用
- react native 学习笔记----网络
- react native 开发框架,封装网络请求,自定义控件,常用工具类
- React Native 网络请求封装:使用Promise封装fetch请求
- React Native 网络请求封装:使用Promise封装fetch请求
- React Native 网络请求封装:使用Promise封装fetch请求
- 基于AFNetworking封装的网络请求工具类【原创】
- 基于AFNetworking封装的网络请求工具类
- Java学习笔记———《http的get请求和post请求及封装的工具类》
- React Native中的网络请求fetch和简单封装
- React Native中的网络请求fetch和简单封装
- ReactNative学习笔记--下拉选择菜单的简单封装
- React Native中的网络请求fetch和简单封装
- React-Native学习笔记 使用ListView加载网络数据
- react native 学习笔记----网络