脱机Meteor / React Native应用程序

时间:2017-10-18 18:22:17

标签: meteor react-native redux

我通常会找到解决Google / Stackoverflow / Meteor论坛问题的方法,或者找人修理它。但是,这次我完全卡住了。这是我的问题:

我用Meteor / React / React Native创建了一个现场服务管理应用程序。管理人员可以在Web应用程序上创建任务/工作单,现场团队可以在移动应用程序上创建报告/工作日志。

但是,我所在的地区在某些地区的互联网连接很差。因此,离线功能对于查看任务/报告以及创建报告(而不是任务)都至关重要。为了解决离线数据访问问题,我遵循了Spencer Carli的优秀教程https://hackernoon.com/offline-first-react-native-meteor-apps-2bee8e976ec7

它运作良好。

创建离线报告出了问题。基本上,我在redux商店中创建了一个动作队列来处理离线报告创建。当连接重新联机时,正在映射操作,在服务器上创建报告,然后删除操作,并从mini mongo和redux中删除脱机创建的报告,因为无论如何,一旦在服务器上创建,它就会再次自动同步。 / p>

它工作得很好但有时候,特别是当互联网连接速度很慢时,会创建重复项。比如,同时报道50多个重复的报告。

以下是动作队列同步:

  async handleSync(props) {
    const data = Meteor.getData();
    const db = data && data.db;

    if (props.loading === false && props.connectionStatus === 'connected' && Meteor.userId() && db && props.actionQueue && props.actionQueue.length > 0) {
      for (let action of props.actionQueue) {
        if (action.msg === 'createReport') {
          const report = {
            organizationId: action.doc.organizationId,
            taskId: action.doc.taskId,
            status: action.doc.status,
            startedAt: action.doc.startedAt,
          };
          const result = await Meteor.call('Reports.create', report, (error, res) => {
            if (error) {
              Alert.alert(I18n.t('main.error'), `${I18n.t('main.errorSyncReport')} ${error.reason}`);
            } else {
              props.dispatch({ type: 'REMOVE_ACTION_QUEUE', payload: action.actionId });
              props.dispatch({ type: 'REMOVE_OFFLINE_REPORT', payload: action.doc._id });
              db['reports'].del(action.doc._id);
              const task = {
                organizationId: action.doc.organizationId,
                taskId: action.doc.taskId,
              };
              Meteor.call('Tasks.updateTaskStatus', task);
            }
          });
          return result;
        } 
        else if (action.msg === 'completeReport') {
          // this action is for completion of reports that have been created online
          const report = {
            organizationId: action.doc.organizationId,
            reportId: action.doc._id,
            comments: action.doc.comments,
            isTaskCompleted: action.doc.isTaskCompleted,
            completedAt: action.doc.completedAt,
            fields: action.doc.fields,
          };
          const result = await Meteor.call('Reports.completeReport', report, (error, res) => {
            if (error) {
              Alert.alert(I18n.t('main.error'), `${I18n.t('main.errorSyncReport')} ${error.reason}`);
            } else {
              props.dispatch({ type: 'REMOVE_ACTION_QUEUE', payload: action.actionId });
              const task = {
                organizationId: action.doc.organizationId,
                taskId: action.doc.taskId,
              };
              Meteor.call('Tasks.updateTaskStatus', task);
            }
          });
          return result;
        }
        else if (action.msg === 'createCompletedReport') {
          // this action is for completion of reports that have been created offline to avoid _id problems
          // so a new completed report is created and the offline report is deleted
          const report = {
            organizationId: action.doc.organizationId,
            taskId: action.doc.taskId,
            comments: action.doc.comments,
            isTaskCompleted: action.doc.isTaskCompleted,
            fields: action.doc.fields,
            status: action.doc.status,
            startedAt: action.doc.startedAt,
            completedAt: action.doc.completedAt,
          };
          const result = await Meteor.call('Reports.create', report, (error, res) => {
            if (error) {
              Alert.alert(I18n.t('main.error'), `${I18n.t('main.errorSyncReport')} ${error.reason}`);
            } else {
              props.dispatch({ type: 'REMOVE_ACTION_QUEUE', payload: action.actionId });
              props.dispatch({ type: 'REMOVE_OFFLINE_REPORT', payload: action.doc._id });
              db['reports'].del(action.doc._id);
              const task = {
                organizationId: action.doc.organizationId,
                taskId: action.doc.taskId,
              };
              Meteor.call('Tasks.updateTaskStatus', task);
            }
          });
          return result;
        }
      }
    }
  }

以下是基于Spencer教程的离线初始化:

const onRehydration = (store) => {
  const data = Meteor.getData();
  const db = data && data.db;
  if (db) {
    _.each(store.getState(), (collectionData, collectionName) => {
      if (collectionName !== 'offlineUser' && collectionName !== 'offlineOrg' && collectionName !== 'actionQueue' && collectionName !== 'clipboard') {
        if (!db[collectionName]) {
          db.addCollection(collectionName);
        }
        const collectionArr = _.map(collectionData, (doc, _id) => {
          doc._id = _id;
          return doc;
        });
        db[collectionName].upsert(collectionArr);
      }
    });
  }
  store.dispatch({type: 'CACHING', caching: false})
};

export const initializeOffline = (opts = {}) => {
  let debug = false;
  const logger = createLogger({ predicate: () => debug&&opts.log || false });
  const store = createStore(reducers, applyMiddleware(logger), autoRehydrate());
  persistStore(store, {
    storage: AsyncStorage,
    keyPrefix: 'offline:',
    debounce: opts.debounce || 2000,
  }, () => onRehydration(store));
  store.dispatch({type: 'CACHING', caching: true})

  Meteor.ddp.on('added', (payload) => {
    store.dispatch({ type: 'DDP_ADDED', payload });
  });

  Meteor.ddp.on('changed', (payload) => {
    store.dispatch({ type: 'DDP_CHANGED', payload });
  });

  Meteor.ddp.on('removed', (payload) => {
    store.dispatch({ type: 'DDP_REMOVED', payload });
  });
  return store;
};

如果有人对此问题有所了解或遇到过类似的问题,如果您能分享您的解决方案,我将不胜感激:)

0 个答案:

没有答案