Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Live query support #10

Merged
merged 5 commits into from
Aug 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 20 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,71 +10,35 @@ MobX and [Tracker](https://docs.meteor.com/api/tracker.html#Tracker-autorun) can
### Usage

```javascript
// my-store.js
import { observable } from 'mobx';

export default observable({
selectedProjectId: null,
projectTodos: []
});

// autorun/todos.js
import state from '../my-store';
import * as Collections from '../../infrastructure/collections';
import { Meteor } from 'meteor/meteor';
import { observable, useStrict } from 'mobx';
import autorun, { observe } from 'meteor/space:tracker-mobx-autorun';

export default () => {
const projectId = state.selectedProjectId;
Meteor.subscribe('todos', {projectId});
// MobX ObservableArray.replace() needs to be used instad of direct assignment
// to keep observable array instance and prevent re-rendering of the whole array
state.projectTodos.replace(Collections.Todos.find({projectId}).fetch());
};

// index.js
import autorun from 'meteor/space:tracker-mobx-autorun';
import todos from './autorun/todos';
// Optionally MobX strict mode makes state in the store immutable, in that case
// state can ony be changed by MobX actions
useStrict(true);

export const todosAutorun = autorun(todos);
const Todos = new Mongo.Collection('todos');

Meteor.startup(function() {
if (Meteor.isClient) {
todosAutorun.start();
}
const state = observable({
selectedProjectId: null,
 projectTodos: []
});

```

### Usage with MobX _strict mode_
Using MobX [actions](https://mobxjs.github.io/mobx/refguide/action.html)
is mandatory when strict mode is enabled.

```javascript
// index.js - enabling MobX strict mode
import { useStrict } from 'mobx';
useStrict(true);

// actions/projects.js
import state from '../store';
import { action } from 'mobx';
const syncProjectTodos = autorun(() => {
 const projectId = state.selectedProjectId;
 const handle = Meteor.subscribe('todos', { projectId });
const cursor = Todos.find({ projectId });
observe('todosAutorun', state.projectTodos, handle, cursor);
});

export const selectProject = action('selectProject', (projectId) => {
state.selectedProjectId = projectId;
// Starting autorun on startup or when needed
Meteor.startup(() => {
 if (Meteor.isClient) syncProjectTodos().start();
});

// autorun/todos.js
import state from '../my-store';
import * as Collections from '../../infrastructure/collections';
import { Meteor } from 'meteor/meteor';
import { action } from 'mobx';

export default () => {
const projectId = state.selectedProjectId;
Meteor.subscribe('todos', {projectId});
action('updateTodosFromAutorun', (todos) => {
state.projectTodos.replace(todos);
})(projectId ? Collections.Todos.find({projectId}).fetch() : []);
};
// Stopping autorun
syncProjectTodos().stop();

```

Expand Down
34 changes: 34 additions & 0 deletions autorun.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Tracker } from 'meteor/tracker';
import { autorun } from 'mobx';

export default (trackerMobxAutorun) => {
let mobxDisposer = null;
let computation = null;
let hasBeenStarted;
return {
start() {
let isFirstRun = true;
computation = Tracker.autorun(() => {
if (mobxDisposer) {
mobxDisposer();
isFirstRun = true;
}
mobxDisposer = autorun(() => {
if (isFirstRun) {
trackerMobxAutorun();
} else {
computation.invalidate();
}
isFirstRun = false;
});
});
hasBeenStarted = true;
},
stop() {
if (hasBeenStarted) {
computation.stop();
mobxDisposer();
}
}
};
};
38 changes: 4 additions & 34 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,10 @@
import { Tracker } from 'meteor/tracker';
import { checkNpmVersions } from 'meteor/tmeasday:check-npm-versions';
import observeCursor from './observe-cursor';
import autorun from './autorun';

checkNpmVersions({
'mobx': '2.x'
}, 'space:tracker-mobx-autorun');

const { autorun } = require('mobx');

export default (trackerMobxAutorun) => {
let mobxDisposer = null;
let computation = null;
let hasBeenStarted;
return {
start() {
let isFirstRun = true;
computation = Tracker.autorun(() => {
if (mobxDisposer) {
mobxDisposer();
isFirstRun = true;
}
mobxDisposer = autorun(() => {
if (isFirstRun) {
trackerMobxAutorun();
} else {
computation.invalidate();
}
isFirstRun = false;
});
});
hasBeenStarted = true;
},
stop() {
if (hasBeenStarted) {
computation.stop();
mobxDisposer();
}
}
};
};
export default autorun;
export const observe = observeCursor;
37 changes: 37 additions & 0 deletions observe-cursor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Tracker } from 'meteor/tracker';
import { action } from 'mobx';

export default (actionPrefix = '', observableArray, handle, cursor) => {

if (handle.ready()) {
// initially fetch all documents and store them in the observable array
Tracker.nonreactive(() => {
action(`${actionPrefix}: initial fetch`, (comments) => {
observableArray.replace(comments);
})(cursor.fetch());
});

// observe changes after initial fetch
cursor.observe({
// _suppress_initial suppresses addedAt callback for documents initially fetched
_suppress_initial: true,
addedAt: action(`${actionPrefix}: document added`, (document, atIndex) => {
observableArray.splice(atIndex, 0, document);
}),
changedAt: action(`${actionPrefix}: document changed`, (newDocument, oldDocument, atIndex) => {
observableArray.splice(atIndex, 1, newDocument);
}),
removedAt: action(`${actionPrefix}: document removed`, (oldDocument, atIndex) => {
observableArray.splice(atIndex, 1);
}),
movedTo: action(`${actionPrefix}: document moved`, (document, fromIndex, toIndex) => {
observableArray.splice(fromIndex, 1);
observableArray.splice(toIndex, 0, document);
}),
});
} else {
action(`${actionPrefix}: initialized`, () => {
observableArray.clear();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

})();
}
};