diff --git a/.gitignore b/.gitignore
index 40b878d..d5733f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-node_modules/
\ No newline at end of file
+node_modules/
+.tern-port
diff --git a/README.md b/README.md
index 50d0078..aa21365 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,16 @@
Meteor Redux Demo
=================
-This repository contains a demonstration application for the article [A bridge between React and Meteor](https://subvisual.co/blog/posts/79-working-with-meteor-react-and-redux). In this application you can write and see messages. If you try to write an empty message you'll see an error.
+This repository contains a demonstration application for the article [A bridge
+between React and
+Meteor](https://subvisual.co/blog/posts/79-working-with-meteor-react-and-redux).
+In this application you can write, remove, and see messages. If you try to write an empty
+message you'll see an error. While the messages are loading you see a
+"loading" message.
-The purpose of this application is to demonstrate a possible setup for Redux on Meteor, most code written here is not acceptable on production application.
+The purpose of this application is to demonstrate a possible setup for Redux on
+Meteor, most code written here is not acceptable on production application.
+
+This application uses the package
+[meteor-ditto](https://github.com/gabrielpoca/meteor-ditto). It's a working in
+progress implementing the system I talk about in the blog post.
diff --git a/client/actions/actions.js b/client/actions/actions.js
index cad0b33..dda33bc 100644
--- a/client/actions/actions.js
+++ b/client/actions/actions.js
@@ -12,3 +12,9 @@ export const createMessage = params => {
});
};
};
+
+export const removeMessage = id => {
+ return () => {
+ Meteor.call('removeMessage', id);
+ };
+};
diff --git a/client/components/MessagesList/MessagesList.jsx b/client/components/MessagesList/MessagesList.jsx
index 5490415..758f2e9 100644
--- a/client/components/MessagesList/MessagesList.jsx
+++ b/client/components/MessagesList/MessagesList.jsx
@@ -1,17 +1,29 @@
import React, { Component, PropTypes } from 'react';
class MessagesList extends Component {
- renderMessage(message, index) {
- return
{message.text};
+ renderMessage({ _id, text }, index) {
+ return (
+
+ {text} this.props.onRemove(_id)}>Remove
+
+ );
+ }
+
+ renderLoading() {
+ return Loading messages...
;
}
render() {
- return {this.props.messages.map(this.renderMessage)}
;
+ if (!this.props.ready)
+ return this.renderLoading();
+ return {this.props.messages.map(this.renderMessage.bind(this))}
;
}
}
MessagesList.propTypes = {
messages: PropTypes.array.isRequired,
+ onRemove: PropTypes.func.isRequired,
+ ready: PropTypes.bool,
};
export default MessagesList;
diff --git a/client/containers/App.jsx b/client/containers/App.jsx
index ece3ce9..e97f53f 100644
--- a/client/containers/App.jsx
+++ b/client/containers/App.jsx
@@ -1,10 +1,10 @@
import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
-import { createMessage } from '../actions/actions';
+import { createMessage, removeMessage } from '../actions/actions';
import { reset } from 'redux-form';
-import SubscribeComponent from '../helpers/SubscribeComponent';
+import { SubscriptionComponent } from 'meteor-ditto';
import MessagesList from '../components/MessagesList/MessagesList';
import MessagesEditor from '../components/MessagesEditor/MessagesEditor';
import Errors from '../components/Errors/Errors';
@@ -19,10 +19,18 @@ class App extends Component {
this.props.reset('new-message');
}
+ handleRemove(id) {
+ this.props.removeMessage(id);
+ }
+
render() {
return (
-
+
@@ -34,18 +42,23 @@ class App extends Component {
App.propTypes = {
subscribe: PropTypes.func.isRequired,
+ subscriptionReady: PropTypes.func.isRequired,
createMessage: PropTypes.func.isRequired,
+ removeMessage: PropTypes.func.isRequired,
reset: PropTypes.func.isRequired,
messages: PropTypes.array.isRequired,
errors: PropTypes.array.isRequired,
};
const mapStateToProps = state => {
- return { messages: state.messages, errors: state.errors };
+ return {
+ messages: state.mongo.collections.messages || [],
+ errors: state.errors,
+ };
};
const mapDispatchToProps = dispatch => {
- return bindActionCreators({ createMessage, reset }, dispatch);
+ return bindActionCreators({ createMessage, removeMessage, reset }, dispatch);
};
-export default connect(mapStateToProps, mapDispatchToProps)(SubscribeComponent(App));
+export default connect(mapStateToProps, mapDispatchToProps)(SubscriptionComponent(App));
diff --git a/client/helpers/SubscribeComponent.jsx b/client/helpers/SubscribeComponent.jsx
deleted file mode 100644
index f924d71..0000000
--- a/client/helpers/SubscribeComponent.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Meteor } from 'meteor/meteor';
-import React, { Component } from 'react';
-
-export default ComposedComponent => class extends Component {
- constructor() {
- super();
- this.subs = {};
- }
-
- subscribe(name, ...args) {
- if (this.subs[name])
- this.subs[name].stop();
-
- this.subs[name] = Meteor.subscribe(name, ...args);
- }
-
- subscriptionReady(name) {
- if (this.subs[name].ready())
- return this.subs[name].ready();
- }
-
- componentWillUnmount() {
- Object.keys(this.subs).map(key => this.subs[key].stop());
- }
-
- render() {
- return (
-
- );
- }
-};
diff --git a/client/reducers/reducers.js b/client/reducers/reducers.js
index 526ba12..c70b7b6 100644
--- a/client/reducers/reducers.js
+++ b/client/reducers/reducers.js
@@ -1,14 +1,6 @@
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
-
-const messagesReducer = (state = [], action) => {
- switch (action.type) {
- case 'SET_MESSAGES':
- return action.messages;
- default:
- return state;
- }
-};
+import { mongo } from 'meteor-ditto';
const errorsReducer = (state = [], action) => {
switch (action.type) {
@@ -20,7 +12,7 @@ const errorsReducer = (state = [], action) => {
};
export default combineReducers({
- messages: messagesReducer,
errors: errorsReducer,
form: formReducer,
+ mongo,
});
diff --git a/client/store/createStore.js b/client/store/createStore.js
index c9a37cd..6169998 100644
--- a/client/store/createStore.js
+++ b/client/store/createStore.js
@@ -1,19 +1,17 @@
-import { Tracker } from 'meteor/tracker';
-import { createStore, applyMiddleware } from 'redux';
+import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
+import { connect as connectCollection } from 'meteor-ditto';
import reducers from '../reducers/reducers';
import Messages from '../../lib/messages';
export default () => {
- const store = createStore(reducers, applyMiddleware(thunk));
+ const store = createStore(reducers, compose(
+ applyMiddleware(thunk),
+ window.devToolsExtension ? window.devToolsExtension() : fn => fn,
+ ));
- Tracker.autorun(() => {
- store.dispatch({
- type: 'SET_MESSAGES',
- messages: Messages.find().fetch(),
- });
- });
+ connectCollection(Messages, store);
return store;
};
diff --git a/package.json b/package.json
index 180344c..ea2829b 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
},
"dependencies": {
"lodash": "^4.11.1",
+ "meteor-ditto": "0.0.4",
"meteor-node-stubs": "~0.2.0",
"react": "^15.0.1",
"react-dom": "^15.0.1",
diff --git a/server/methods.js b/server/methods.js
index 0c3af96..b1ff9ca 100644
--- a/server/methods.js
+++ b/server/methods.js
@@ -8,6 +8,14 @@ const createMessage = function(params) {
Messages.insert(params);
};
+const removeMessage = function(_id) {
+ if (!_id)
+ throw new Meteor.Error('id missing', 'An id is needed to remove a message');
+
+ Messages.remove({ _id });
+};
+
Meteor.methods({
createMessage,
+ removeMessage,
});