├── .gitignore ├── README.md ├── app.js ├── components ├── AppRoot.jsx └── NewItemForm.jsx ├── config.js ├── dispatcher └── AppDispatcher.js ├── dist └── bundle.js ├── index.html ├── package.json ├── stores └── ListStore.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-flux-cosmicjs 2 | This is an extenstion of the [easy-flux-example repo](https://github.com/tonyspiro/easy-flux-example). This repo demonstrates how to build a data-driven [React](http://facebook.github.io/react/) application using the [Flux](https://facebook.github.io/flux/) pattern and the [Cosmic JS browser client](https://www.npmjs.com/package/cosmicjs-browser) to perform read / write / delete operations on the [Cosmic JS API](https://cosmicjs.com). 3 | 4 | ##Getting started 5 | 1. Sign up for Cosmic JS and add a bucket: [https://cosmicjs.com](https://cosmicjs.com) 6 | 2. Install the repo 7 | 8 | ```git clone https://github.com/tonyspiro/react-flux-cosmicjs ``` 9 | 10 | 3. Configure config.js to point to your Cosmic JS bucket 11 | ``` 12 | // config.js 13 | 14 | let config = {}; 15 | config.bucket = { 16 | slug: 'react-flux-cosmicjs', // your Cosmic JS bucket slug 17 | read_key: '', // add read_key if added to your Cosmic JS bucket settings 18 | write_key: '' // add write_key if added to your Cosmic JS bucket settings 19 | }; 20 | 21 | export default config; 22 | ``` 23 | 4. Run webpack-dev-server 24 | 25 | ``` 26 | cd react-flux-cosmicjs 27 | npm install 28 | npm run dev 29 | ``` 30 | Go to [http://localhost:8080/webpack-dev-server/](http://localhost:8080/webpack-dev-server/) 31 | 32 | 5. Production ready (minified) 33 | ``` 34 | npm run prod 35 | ``` 36 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AppRoot from './components/AppRoot.jsx'; 3 | 4 | React.render( 5 | , 6 | document.getElementById('app-root') 7 | ); 8 | -------------------------------------------------------------------------------- /components/AppRoot.jsx: -------------------------------------------------------------------------------- 1 | // AppRoot.jsx 2 | import React from 'react'; 3 | import ListStore from '../stores/ListStore'; 4 | import AppDispatcher from '../dispatcher/AppDispatcher'; 5 | 6 | // Sub components 7 | import NewItemForm from './NewItemForm.jsx'; 8 | 9 | // Method to retrieve state from Stores 10 | let getListState = () => { 11 | return { 12 | items: ListStore.getItems() 13 | }; 14 | } 15 | 16 | class AppRoot extends React.Component { 17 | 18 | // Method to setState based upon Store changes 19 | _onChange() { 20 | this.setState(getListState()); 21 | } 22 | 23 | constructor() { 24 | 25 | super(); 26 | 27 | // API data 28 | AppDispatcher.dispatch({ 29 | action: 'init-app' 30 | }); 31 | 32 | } 33 | 34 | // Add change listeners to stores 35 | componentDidMount() { 36 | ListStore.addChangeListener(this._onChange.bind(this)); 37 | } 38 | 39 | // Remove change listeners from stores 40 | componentWillUnmount() { 41 | ListStore.removeChangeListener(this._onChange.bind(this)); 42 | } 43 | 44 | removeItem(e){ 45 | 46 | let _id = e.target.dataset._id; 47 | 48 | AppDispatcher.dispatch({ 49 | action: 'remove-item', 50 | _id: _id 51 | }); 52 | } 53 | 54 | render(){ 55 | 56 | let _this = this; 57 | 58 | let items = ListStore.getItems(); 59 | let itemHtml = items.map(( listItem ) => { 60 | return
  • 61 | { listItem.title } 62 |
  • ; 63 | }); 64 | 65 | return ( 66 |
    67 | 70 | 71 |
    72 | ); 73 | } 74 | } 75 | 76 | export default AppRoot; 77 | -------------------------------------------------------------------------------- /components/NewItemForm.jsx: -------------------------------------------------------------------------------- 1 | // NewItemForm.jsx 2 | import React from 'react'; 3 | import AppDispatcher from '../dispatcher/AppDispatcher'; 4 | 5 | class NewItemForm extends React.Component { 6 | 7 | createItem(e){ 8 | 9 | // so we don't reload the page 10 | e.preventDefault(); 11 | 12 | // this gets the value from the input 13 | let item_title = React.findDOMNode(this.refs.item_title).value.trim(); 14 | 15 | if(!item_title) return false; 16 | 17 | // this removes the value from the input 18 | React.findDOMNode(this.refs.item_title).value = ''; 19 | 20 | // This is where the magic happens, 21 | // no need to shoot this action all the way to the root of your application to edit state. 22 | // AppDispatcher does this for you. 23 | AppDispatcher.dispatch({ 24 | action: 'add-item', 25 | new_item: { 26 | title: item_title 27 | } 28 | }); 29 | 30 | } 31 | 32 | render(){ 33 | 34 | return
    35 | 36 | 37 |
    38 | } 39 | } 40 | 41 | export default NewItemForm; 42 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | /* Configure 2 | ================================ */ 3 | let config = {}; 4 | config.bucket = { 5 | slug: 'react-flux-cosmicjs', // this is your Cosmic JS bucket slug. Sign up for Cosmic JS (Free) and add a bucket: https://cosmicjs.com/ 6 | read_key: '', // add read_key if added to your Cosmic JS bucket settings 7 | write_key: '' // add write_key if added to your Cosmic JS bucket settings 8 | }; 9 | 10 | export default config; -------------------------------------------------------------------------------- /dispatcher/AppDispatcher.js: -------------------------------------------------------------------------------- 1 | // AppDispatcher.js 2 | import {Dispatcher} from 'flux'; 3 | let AppDispatcher = new Dispatcher(); 4 | 5 | import ListStore from '../stores/ListStore'; 6 | 7 | // Register callback with AppDispatcher 8 | AppDispatcher.register((payload) => { 9 | 10 | let action = payload.action; 11 | 12 | switch(action) { 13 | 14 | case 'init-app': 15 | 16 | ListStore.init(); 17 | 18 | break; 19 | 20 | // Respond to add-item action 21 | case 'add-item': 22 | 23 | ListStore.addItem(payload); 24 | 25 | break; 26 | 27 | // Respond to remove-item action 28 | case 'remove-item': 29 | 30 | ListStore.removeItem(payload); 31 | 32 | break; 33 | 34 | default: 35 | 36 | return true; 37 | 38 | } 39 | 40 | return true; 41 | 42 | }); 43 | 44 | export default AppDispatcher; 45 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Flux Cosmic JS 6 | 7 | 8 |

    React Flux Cosmic JS

    9 |
    10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easy-flux-cosmicjs", 3 | "version": "1.0.0", 4 | "description": "This is an extenstion of the [easy-flux-example repo](https://github.com/tonyspiro/easy-flux-example). This repo also demonstrates how to easily add the Cosmic JS browser client to perform read / write / delete operations on given data sets.", 5 | "main": "app.js", 6 | "dependencies": { 7 | "cosmicjs": "^2.0.0", 8 | "es6-promise": "^3.0.2", 9 | "events": "^1.0.2", 10 | "flux": "^2.1.1", 11 | "isomorphic-fetch": "^2.2.0", 12 | "lodash": "^3.10.1", 13 | "react": "^0.13.3" 14 | }, 15 | "devDependencies": { 16 | "babel-core": "^5.8.25", 17 | "babel-loader": "^5.3.2" 18 | }, 19 | "scripts": { 20 | "watch": "webpack --watch", 21 | "dev": "webpack-dev-server", 22 | "prod": "webpack -p", 23 | "test": "echo \"Error: no test specified\" && exit 1" 24 | }, 25 | "author": "Tony Spiro (http://tonyspiro.com/)", 26 | "license": "ISC" 27 | } 28 | -------------------------------------------------------------------------------- /stores/ListStore.js: -------------------------------------------------------------------------------- 1 | // ListStore.js 2 | import {EventEmitter} from 'events'; 3 | import _ from 'lodash'; 4 | import Cosmic from 'cosmicjs'; 5 | import config from './../config'; 6 | 7 | let ListStore = _.extend({}, EventEmitter.prototype, { 8 | 9 | // Initial data 10 | items: [], 11 | 12 | // Init items from Cosmic JS 13 | init: function(items){ 14 | 15 | let _this = this; 16 | 17 | Cosmic.getObjects(config, function(err, response){ 18 | 19 | let items = response.objects.type['list-items']; 20 | items = _.sortBy(items, 'order'); 21 | _this.items = items; 22 | _this.emitChange(); 23 | 24 | }); 25 | }, 26 | 27 | // Get all items 28 | getItems: function(){ 29 | return this.items; 30 | }, 31 | 32 | // Add item 33 | addItem: function(payload){ 34 | 35 | let new_item = payload.new_item; 36 | let _this = this; 37 | let object = { 38 | type_slug: 'list-items', 39 | title: new_item.title 40 | }; 41 | 42 | Cosmic.addObject(config, object, function(err, response){ 43 | 44 | if(response.object){ 45 | let new_cosmic_item = response.object; 46 | _this.items.push(new_cosmic_item); 47 | _this.emitChange(); 48 | } 49 | 50 | }); 51 | }, 52 | 53 | // Remove item 54 | removeItem: function(payload){ 55 | 56 | let _id = payload._id; 57 | let _this = this; 58 | let delete_object = { 59 | _id: _id 60 | }; 61 | 62 | Cosmic.deleteObject(config, delete_object, function(err, object){ 63 | 64 | let items = _this.items; 65 | 66 | _.remove(items,(item) => { 67 | return _id == item._id; 68 | }); 69 | 70 | _this.items = items; 71 | _this.emitChange(); 72 | 73 | }); 74 | 75 | }, 76 | 77 | // Emit Change event 78 | emitChange: function(){ 79 | this.emit('change'); 80 | }, 81 | 82 | // Add change listener 83 | addChangeListener: function(callback){ 84 | this.on('change', callback); 85 | }, 86 | 87 | // Remove change listener 88 | removeChangeListener: function(callback) { 89 | this.removeListener('change', callback); 90 | } 91 | 92 | }); 93 | 94 | export default ListStore; 95 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './app.js', 3 | output: { path: __dirname, filename: 'dist/bundle.js' }, 4 | module: { 5 | loaders: [ 6 | { test: /.jsx?$/, loader: 'babel-loader', exclude: /node_modules/ } 7 | ] 8 | }, 9 | }; --------------------------------------------------------------------------------