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
複製代碼
相關文章
相關標籤/搜索