React 与 React-Native 使用同一个 meteor 后台

meteor 能够快速构建 pc,移动端,桌面端应用。css

最大的优势是:数据库的数据发生变化时,能够实时推送到前端,很是适用于实时展现的应用开发。前端

在 react,react-native 应用中,能够仅使用同一个 meteor 后台,实时向前端推送数据。react

github 代码地址git

metaor 安装

windows 安装 meteor

官方推荐 chocolatey 安装 meteor。github

  1. 先从 chocolatey 安装 chocolatey
  2. 而后在命令行中运行 choco install meteor

可是 meteor 安装速度很是慢,一顿搜索以后,找到了 Windows 下经过二进制包安装的下载地址 install.meteor.com/windows,搜索来源 github.com/meteor/docs…web

OSX/Linux 安装 meteor

安装很是简单mongodb

curl https://install.meteor.com/ | sh
复制代码

验证安装

命令行输入shell

meteor --version
复制代码

输出版本号,表示安装成功数据库

Meteor 1.8.1
复制代码

mongodb 安装

windows 安装 mongodb

www.mongodb.com/ 下载安装包安装windows

OSX 安装 mongodb

brew install mongod
复制代码

或者下载二进制包安装

mongod ,不是 mongodb

mongodb 图形界面

推荐 robomongo.org/, 易于使用,也是免费的。

meteor DDP

react,react-native 使用同一个 meteor 后台,因此 meteor 后台要与前端应用分开编写。

这就涉及到 meteor 中后台与前端的数据交互,meteor 中定义了一个 DDP协议

DDP协议定义了 meteor 后台发布数据,客户端订阅数据的操做。

本应用使用已经编写好了的 DDP 协议库,地址以下: github.com/mondora/ddp…

建立 meteor 项目

meteor create --bare [project-name]
复制代码

更多建立参数

meteor help create
复制代码

meteor 链接 mongodb

meteor 项目启动命令以下:

meteor run
复制代码

配置端口

meteor run --port 9090
复制代码

meteor 链接本身的 mongodb

meteor 安装包中集成了 mongodb,默认启动的是集成的 mongodb。 为了链接本身的 mongodb,须要传入参数

MONGO_URL=mongodb://username:password@localhost:27017/[database-name]?authSource=admin meteor  run --port 9090
复制代码

刚开始没加上 authSource=admin 参数,一直链接不上 mongodb,加上以后就行了,根据须要加。

更多链接参数

编写 meteor 后台

import {Meteor} from 'meteor/meteor'; 
// mongodb 的 todo collection 
const Todo = new Meteor.Collection('todo');
// 发布数据,前端就能够调用
Meteor.publish('todo', () => {
    return Todo.find();
});
/** * 定义前端调用的方法 */
Meteor.methods({
    // 查找一条数据
    getTodo(id) {
        return Todo.findOne(id);
    },
    // 查找全部数据
    getAllTodo() {
        return Todo.find().fetch();
    },
    // 新增
    addTodo(item) {
        return Todo.insert(item);
    },
    // 删除
    removeTodo(id) {
        return Todo.remove({_id: id});
    },
    // 编辑
    editTodo(item) {
        return Todo.update({_id: item.id}, {$set: item});
    },
    /** * * @param {number 当前页面 从 1 开始} currentPage * @param {number 单次请求总条数} pageSize */
    getPageTodo(currentPage = 1, pageSize = 10) {
        if (page < 1) {
            return null;
        }
        // meteor 对 mongodb 的操做方法作了封装
        // 更多操做请查看 meteor 官方文档
        const total = Todo.find().count();
        const list = Todo.find(
            {},
            {
                skip: (currentPage - 1) * pageSize,
                limit: pageSize,
            }
        ).fetch();
        return {total, data: list};
    },
});
// 定义对 mongodb 的操做权限
// 若没有定义,则是容许全部增删改查操做
Todo.deny({
    // 是否容许 mongodb 的新增操做, 返回 true 表示容许,不然不容许
    insert() {
        return true;
    },
    update() {
        return true;
    },
    remove() {
        return true;
    },
});

export default Todo;
复制代码

前端调用

定义高阶组件

为了代码复用,定义了高阶组件,react 与 react-native 能够共用

// meteor.js
import React, {Component} from 'react';
import DDP from 'ddp.js';
/** * meteor 链接选项 */
const meteorOptions = {
  endpoint: 'ws://192.168.31.121:9090/websocket',// react-native 不支持 localhost,127.0.0.1,请替换为本身的 IPv4 地址
  SocketConstructor: WebSocket,
  reconnectInterval: 10000,// 重连间隔
  autoConnect: true,// 是否自动链接
  autoReconnect: true,// 是否自动重连
};
const PUBLIC_EVENTS = [
  // 'ready',
  // 'nosub',
  'added',
  'changed',
  'removed',
  // 'result',
  // 'updated',
  // 'error',
];
export default (WrapperComponent, {collectionName, methodName}) => {
  class MeteorWrapper extends Component {
    ddp = new DDP(meteorOptions);
    lockRequest = false
    recordSubscriptions = {};
    state = {
      meteorList: [],
      initOver: false,
    };

    componentDidMount() {
      if (!this.ddp) {
        console.error(`数据推送未链接上服务器!`);
        return;
      }
      // 添加订阅
      this.addSubscription();
    }

    componentWillUnmount() {
      // 取消订阅
      this.removeSubscription();
      // 断开链接
      this.ddp.disconnect();
    }

    getDataResult() {
      // 防止初始化请求次数过多
      if (this.lockRequest) {
        return
      }
      this.lockRequest = true
      const {ddp} = this;
      const self = this;
      /** * 调用后台定义的方法, 前端传递数组参数,meteor 后台接受到的是列表参数 */
      ddp.method(methodName, [1, 10]);
      ddp.on('result', data => {
        const {result} = data;
        console.log(data);
        self.setState({
          meteorList: result,
          initOver: true,
        });
        self.lockRequest = false
      });
    }

    componentDidCatch(error, info) {
      console.error(error, info);
    }

    addSubscription() {
      if (!collectionName) {
        console.error('mongodb collection 为空!');
        return;
      }
      const {ddp} = this;
      const self = this;
      // 订阅数据
      self.recordSubscriptions[collectionName] = ddp.sub(collectionName);
      PUBLIC_EVENTS.forEach(event => {
        ddp.on(event, () => {
          console.log(event)
          self.getDataResult();
        });
      });
      ddp.on('error', error => {
        console.error(`服务器推送数据错误,错误消息:${error}`)
      });
      ddp.on('ready', () => {
        self.getDataResult();
      });
    }

    removeSubscription() {
      this.ddp.unsub(this.recordSubscriptions[collectionName]);
    }

    render() {
      return <WrapperComponent {...this.props} {...this.state} />; } } return MeteorWrapper; }; 复制代码

react 使用示例

import React, {Component} from 'react';
import {List, Skeleton} from 'antd';
import './App.css';
import MeteorWrapper from './meteor'

function App(props) {
  const {meteorList = [], initOver} = props
  return (
    <div className="App">
      <List
        itemLayout="horizontal"
        dataSource={meteorList}
        renderItem={item => (
          <List.Item key={item.id}>
            <Skeleton loading={!initOver} active avatar>
              <List.Item.Meta
                title={item.name}
                description={item.desc}
              />
            </Skeleton>

          </List.Item>
        )}
      />
    </div>
  );
}

export default MeteorWrapper(App, {
  collectionName:'todo',
  methodName:'getAllTodo'
})

复制代码

react-native 使用示例

import React  from 'react';
import {StyleSheet, Text, View, FlatList} from 'react-native';
import MeteorWrapper from './meteor'

function App(props) {
  const {meteorList = [], initOver} = props
  return (
    <View style={styles.container}> <FlatList data={meteorList} renderItem={({item}) => ( <View style={styles.item}> <View style={styles.name}><Text>{item.name}</Text></View> <View style={styles.desc}><Text>{item.desc}</Text></View> </View>)} /> </View> ); } export default MeteorWrapper(App, { collectionName:'todo', methodName:'getAllTodo' }) const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', fontSize: 14, lineHeight: 2, }, item: { padding: 10, borderColor: '#ccc', borderBottomWidth: 1, borderStyle: 'solid', }, name: { color: '#000', fontWeight: "900", fontSize: 24 }, desc: { color: '#666' } }); 复制代码

开启远程调试

运行命令

adb shell input keyevent 82
复制代码

点击 dev setting 而后点击 Debug server host & port for device 设置为 127.0.0。1:8081

再次运行

adb shell input keyevent 82
复制代码

点击 Debug js remote ,就会自动弹出调试页面。

IOS 运行报错

错误信息以下,请查看解决 React-Native mac10.14.4 运行报错 error Failed to build iOS project

error Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65. To debug build logs further, consider building your app with Xcode.app, by opening reactNative.xcodeproj
复制代码
相关文章
相关标签/搜索