我通常会找到解决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;
};
如果有人对此问题有所了解或遇到过类似的问题,如果您能分享您的解决方案,我将不胜感激:)