├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist.js ├── lib └── .gitkeep ├── package.json ├── src ├── dist.js ├── index.js ├── listener.js └── socket.js └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "es2015", 5 | "stage-2" 6 | ] 7 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env" : { 4 | "browser": true 5 | }, 6 | "rules" : { 7 | "no-class-assign" : 2, 8 | "no-confusing-arrow" : 0, 9 | "no-const-assign" : 2, 10 | "no-dupe-class-members" : 2, 11 | "no-new-symbol" : 2, 12 | "no-this-before-super" : 2, 13 | "no-useless-constructor" : 2, 14 | "no-var" : 2, 15 | "arrow-body-style" : [2, "as-needed"], 16 | "arrow-parens" : 0, 17 | "arrow-spacing" : [ 18 | 2, 19 | { 20 | "before": true, 21 | "after" : true 22 | } 23 | ], 24 | "constructor-super" : 2, 25 | "object-shorthand" : [2, "always"], 26 | "prefer-arrow-callback" : 2, 27 | "prefer-const" : 2, 28 | "prefer-rest-params" : 2, 29 | "prefer-spread" : 2, 30 | "prefer-template" : 1, 31 | "template-curly-spacing" : [2, "always"], 32 | "strict" : 0, 33 | "new-cap" : 0, 34 | "eqeqeq" : 2, 35 | "curly" : 2, 36 | "quotes" : [1, "single"], 37 | "no-unreachable" : 2, 38 | "space-before-blocks" : 2, 39 | "space-before-function-paren": 2, 40 | "no-multi-spaces" : 0, 41 | "key-spacing" : 0, 42 | "no-mixed-requires" : 0 43 | } 44 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .idea 4 | *.log 5 | .nyc_output 6 | .nyc_cache 7 | /coverage 8 | /lib/* 9 | !/lib/.gitkeep 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | dist.js 2 | src 3 | test.js 4 | *.test.js -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js : 3 | - "iojs" 4 | deploy: 5 | provider: npm 6 | email: eduardo@comakai.com 7 | api_key: 8 | secure: JX1zgdfsP3rwISjl2mn6LNFOwNYcy2XIuL1mHXhAllDE5utvvaum8/zt/PWuBY7qlocGN8NZfjDsWc3PlDiezs9o0JZ0y0ipBgcPLPJJqbXc6U5EIVAUwnOMs7HorF1yz4S5T4GfBWwWfhFPr3setSHmRDTKyjmUBUqnvUj9Pq8= 9 | on: 10 | tags: true 11 | repo: coma/react-socket -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Eduardo García Sanz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | react-socket 2 | ============ 3 | 4 | [![Build Status](https://travis-ci.org/coma/react-socket.png?branch=master)](https://travis-ci.org/coma/react-socket) 5 | [![Dependency Status](https://david-dm.org/coma/react-socket.png)](http://david-dm.org/coma/react-socket) 6 | [![NPM version](https://badge.fury.io/js/react-socket.png)](http://badge.fury.io/js/react-socket) 7 | 8 | A React wrapper for Socket.IO 9 | 10 | Usage 11 | ----- 12 | 13 | Just mount a socket on one of your components: 14 | 15 | ```javascript 16 | var React = require('react'), 17 | Socket = require('react-socket').Socket; 18 | 19 | module.exports = module.exports = React.createClass({ 20 | render: function () { 21 | 22 | return ( 23 |
24 | 25 |
26 | ); 27 | } 28 | }); 29 | ``` 30 | 31 | and then start listening to it: 32 | 33 | ```javascript 34 | var React = require('react'), 35 | SocketEvent = require('react-socket').Event; 36 | 37 | module.exports = module.exports = React.createClass({ 38 | onSocketMessage: function (message) { 39 | 40 | ... 41 | }, 42 | render: function () { 43 | 44 | return ( 45 |
46 | 47 |
48 | ); 49 | } 50 | }); 51 | ``` 52 | 53 | Use the name property to mount more than one socket: 54 | 55 | ```javascript 56 | var React = require('react'), 57 | Socket = require('react-socket'); 58 | 59 | module.exports = module.exports = React.createClass({ 60 | render: function () { 61 | 62 | return ( 63 |
64 | 65 | 66 | 67 | 68 |
69 | ); 70 | } 71 | }); 72 | ``` 73 | 74 | Every mounted socket gets disconnect before its component gets unmounted and the same goes to the events. -------------------------------------------------------------------------------- /dist.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,t,n){Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=35)}([function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(e){if(l===setTimeout)return setTimeout(e,0);if((l===n||!l)&&setTimeout)return l=setTimeout,setTimeout(e,0);try{return l(e,0)}catch(t){try{return l.call(null,e,0)}catch(t){return l.call(this,e,0)}}}function i(e){if(p===clearTimeout)return clearTimeout(e);if((p===r||!p)&&clearTimeout)return p=clearTimeout,clearTimeout(e);try{return p(e)}catch(t){try{return p.call(null,e)}catch(t){return p.call(this,e)}}}function a(){v&&d&&(v=!1,d.length?y=d.concat(y):h=-1,y.length&&u())}function u(){if(!v){var e=o(a);v=!0;for(var t=y.length;t;){for(d=y,y=[];++h1)for(var n=1;n1?t-1:0),r=1;r2?r-2:0),i=2;i1){for(var N=Array(b),_=0;_1){for(var N=Array(b),_=0;_.")}return t}function i(e,n){if(e._store&&!e._store.validated&&null==e.key){e._store.validated=!0;var r=h.uniqueKey||(h.uniqueKey={}),i=o(n);if(!r[i]){r[i]=!0;var a="";e&&e._owner&&e._owner!==c.current&&(a=" It was passed a child from "+e._owner.getName()+"."),"production"!==t.env.NODE_ENV?v(!1,'Each child in an array or iterator should have a unique "key" prop.%s%s See https://fb.me/react-warning-keys for more information.%s',i,a,s.getCurrentStackAddendum(e)):void 0}}}function a(e,t){if("object"==typeof e)if(Array.isArray(e))for(var n=0;n1?u-1:0),s=1;s>",k={array:a("array"),bool:a("boolean"),func:a("function"),number:a("number"),object:a("object"),string:a("string"),symbol:a("symbol"),any:u(),arrayOf:c,element:s(),instanceOf:l,node:y(),objectOf:f,oneOf:p,oneOfType:d,shape:v};o.prototype=Error.prototype,e.exports=k}).call(t,n(0))},function(e,t,n){"use strict";function r(e,t,n){this.props=e,this.context=t,this.refs=c,this.updater=n||u}function o(){}var i=n(5),a=n(9),u=n(11),c=n(8);o.prototype=a.prototype,r.prototype=new o,r.prototype.constructor=r,i(r.prototype,a.prototype),r.prototype.isPureReactComponent=!0,e.exports=r},function(e,t){"use strict";e.exports="15.3.1"},function(e,t,n){"use strict";(function(t){function r(e,r,p,f,d,y){for(var v in e)if(e.hasOwnProperty(v)){var h;try{"function"!=typeof e[v]?"production"!==t.env.NODE_ENV?c(!1,"%s: %s type `%s` is invalid; it must be a function, usually from React.PropTypes.",f||"React class",a[p],v):i("84",f||"React class",a[p],v):void 0,h=e[v](r,v,f,p,null,u)}catch(m){h=m}if("production"!==t.env.NODE_ENV?s(!h||h instanceof Error,"%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).",f||"React class",a[p],v,typeof h):void 0,h instanceof Error&&!(h.message in l)){l[h.message]=!0;var E="";"production"!==t.env.NODE_ENV&&(o||(o=n(10)),null!==y?E=o.getStackAddendumByID(y):null!==d&&(E=o.getCurrentStackAddendum(d))),"production"!==t.env.NODE_ENV?s(!1,"Failed %s type: %s%s",p,h.message,E):void 0}}}var o,i=n(4),a=n(12),u=n(19),c=n(2),s=n(1);"undefined"!=typeof t&&t.env&&"test"===t.env.NODE_ENV&&(o=n(10));var l={};e.exports=r}).call(t,n(0))},function(e,t,n){"use strict";(function(t){function r(e){return i.isValidElement(e)?void 0:"production"!==t.env.NODE_ENV?a(!1,"React.Children.only expected to receive a single React element child."):o("143"),e}var o=n(4),i=n(3),a=n(2);e.exports=r}).call(t,n(0))},function(e,t,n){"use strict";(function(t){function r(e,t){return e&&"object"==typeof e&&null!=e.key?p.escape(e.key):t.toString(36)}function o(e,n,i,h){var m=typeof e;if("undefined"!==m&&"boolean"!==m||(e=null),null===e||"string"===m||"number"===m||c.isValidElement(e))return i(h,e,""===n?d+r(e,0):n),1;var E,g,b=0,N=""===n?d:n+y;if(Array.isArray(e))for(var _=0;_ SOCKETS.hasOwnProperty(name); 8 | 9 | export const get = (name = NAME) => { 10 | 11 | if (!has(name)) { 12 | 13 | throw new Error(`There is no "${ name }" socket mounted.`); 14 | } 15 | 16 | return SOCKETS[name]; 17 | }; 18 | 19 | class Socket extends Component { 20 | 21 | componentWillMount () { 22 | 23 | const {name, url, options} = this.props; 24 | 25 | if (has(name)) { 26 | 27 | throw new Error(`Another "${ name }" socket is already mounted.`); 28 | } 29 | 30 | SOCKETS[name] = io(url, options); 31 | } 32 | 33 | componentWillUnmount () { 34 | 35 | const {name} = this.props; 36 | 37 | SOCKETS[name].disconnect(); 38 | delete SOCKETS[name]; 39 | } 40 | 41 | render () { 42 | 43 | return false; 44 | } 45 | } 46 | 47 | Socket.displayName = 'Socket'; 48 | 49 | Socket.propTypes = { 50 | url : PropTypes.string, 51 | name : PropTypes.string, 52 | options: PropTypes.object 53 | }; 54 | 55 | Socket.defaultProps = { 56 | url : '/', 57 | name: NAME 58 | }; 59 | 60 | export default Socket; -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const path = require('path'), 2 | glob = require('glob'), 3 | tape = require('tape'), 4 | report = require('faucet'), 5 | ignore = require('ignore-styles'); 6 | 7 | tape 8 | .createStream() 9 | .pipe(report()) 10 | .pipe(process.stdout); 11 | 12 | let files = process.argv.slice(2); 13 | 14 | if (files.length < 1) { 15 | 16 | files = glob.sync('src/**/*.test.js'); 17 | } 18 | 19 | files.map(file => require(path.resolve(__dirname, file))); --------------------------------------------------------------------------------