├── .gitignore ├── LICENSE.md ├── README.md ├── ampersand-react-mixin.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2015 &yet, LLC and AmpersandJS contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ampersand-react-mixin 2 | 3 | Mixin for react classes to easily listen for changes and re-render from ampersand models/collections. 4 | 5 | 6 | ## How it works 7 | 8 | This auto-listens to any ampersand model or collection that is passed to it as a `prop`. And re-renders the component on changes. It also unregisters the listener when the component is unmounted. 9 | 10 | You can also optionally create a method in your component called: `getObservedItems`. 11 | 12 | This will get called to determine which things should be watched. 13 | 14 | Or you can explicitly call `watch` on the component and pass an ampersand model, state, or collection object. 15 | 16 | If it's a collection, it listens to `'add remove reset sort'` events. If it's a `State` object, it listens to `'change'` events. 17 | 18 | ## install 19 | 20 | ``` 21 | npm install ampersand-react-mixin 22 | ``` 23 | 24 | ## example 25 | 26 | ```javascript 27 | var React = require('react'); 28 | var ampersandMixin = require('ampersand-react-mixin'); 29 | 30 | module.exports = React.createClass({ 31 | mixins: [ampersandMixin], 32 | render: function () { 33 | return ( 34 |
35 | ) 36 | } 37 | }) 38 | 39 | ``` 40 | 41 | ## license 42 | 43 | MIT 44 | 45 | -------------------------------------------------------------------------------- /ampersand-react-mixin.js: -------------------------------------------------------------------------------- 1 | var events = require('ampersand-events'); 2 | var bind = require('lodash/bind'); 3 | var forEach = require('lodash/forEach'); 4 | 5 | var deferbounce = function (fn) { 6 | var triggered = false; 7 | return function () { 8 | var self = this; 9 | if (!triggered) { 10 | triggered = true; 11 | setTimeout(function() { 12 | fn.call(self); 13 | triggered = false; 14 | }, 0) 15 | } 16 | } 17 | }; 18 | 19 | var safeForceUpdate = function () { 20 | if (this.isMounted()) { 21 | this.forceUpdate(); 22 | } 23 | }; 24 | 25 | module.exports = events.createEmitter({ 26 | 27 | watch: function (modelOrCollection, opts) { 28 | var events; 29 | 30 | if (modelOrCollection !== null && typeof modelOrCollection === 'object'){ 31 | if (modelOrCollection.isCollection) { 32 | events = 'add remove reset sort'; 33 | } else if (modelOrCollection.isState) { 34 | events = 'change'; 35 | } 36 | } 37 | 38 | if (!events){ 39 | return; 40 | } 41 | 42 | this.listenTo(modelOrCollection, events, deferbounce(bind(safeForceUpdate, this))); 43 | 44 | if (opts.reRender) safeForceUpdate.call(this); 45 | }, 46 | 47 | componentDidMount: function () { 48 | var watched = this.getObservedItems && this.getObservedItems(); 49 | if (watched) { 50 | forEach(watched, this.watch, this); 51 | } 52 | if (this.autoWatch !== false) { 53 | forEach(this.props, this.watch, this); 54 | } 55 | }, 56 | 57 | componentWillUnmount: function () { 58 | this.stopListening(); 59 | } 60 | }); 61 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ampersand-react-mixin", 3 | "version": "2.0.0", 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "ampersand-events": { 7 | "version": "2.0.2", 8 | "resolved": "https://registry.npmjs.org/ampersand-events/-/ampersand-events-2.0.2.tgz", 9 | "integrity": "sha1-9AK8LhgwX6vZldvc07cFe73X00c=" 10 | }, 11 | "ampersand-version": { 12 | "version": "1.0.2", 13 | "resolved": "https://registry.npmjs.org/ampersand-version/-/ampersand-version-1.0.2.tgz", 14 | "integrity": "sha1-/489TOrE0yzNg/a9Zpc5f3tZ4sA=" 15 | }, 16 | "core-util-is": { 17 | "version": "1.0.2", 18 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 19 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 20 | }, 21 | "find-root": { 22 | "version": "0.1.2", 23 | "resolved": "https://registry.npmjs.org/find-root/-/find-root-0.1.2.tgz", 24 | "integrity": "sha1-mNImfP8ZFsyvJ0OzoO6oHXnX3NE=" 25 | }, 26 | "inherits": { 27 | "version": "2.0.3", 28 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 29 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 30 | }, 31 | "isarray": { 32 | "version": "0.0.1", 33 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 34 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 35 | }, 36 | "lodash": { 37 | "version": "4.17.4", 38 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 39 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" 40 | }, 41 | "readable-stream": { 42 | "version": "1.0.34", 43 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 44 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=" 45 | }, 46 | "string_decoder": { 47 | "version": "0.10.31", 48 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 49 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 50 | }, 51 | "through2": { 52 | "version": "0.6.5", 53 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", 54 | "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=" 55 | }, 56 | "xtend": { 57 | "version": "4.0.1", 58 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 59 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ampersand-react-mixin", 3 | "description": "Mixin for react classes to easily listen for changes and re-render from ampersand models/collections", 4 | "version": "2.0.0", 5 | "author": "Henrik Joreteg ", 6 | "bugs": { 7 | "url": "https://github.com/ampersandjs/ampersand-react-mixin/issues" 8 | }, 9 | "dependencies": { 10 | "ampersand-events": "^2.0.2", 11 | "lodash": "^4.17.4" 12 | }, 13 | "homepage": "https://github.com/ampersandjs/ampersand-react-mixin", 14 | "keywords": [ 15 | "ampersand", 16 | "mixin", 17 | "react" 18 | ], 19 | "license": "MIT", 20 | "main": "ampersand-react-mixin.js", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/ampersandjs/ampersand-react-mixin" 24 | }, 25 | "scripts": { 26 | "test": "echo \"Error: no test specified\" && exit 1" 27 | } 28 | } 29 | --------------------------------------------------------------------------------