├── .gitignore ├── .npmignore ├── AUTHORS ├── LICENSE ├── README.md ├── index.js ├── package.json ├── src ├── __specs__ │ └── create.spec.js ├── create.js └── to-stores.js └── test ├── mocha.opts └── utils ├── babel-register.js ├── dom.js └── react-warnings.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | __specs__/ -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Jake Trent 2 | Justin Hewlett -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Deprecated 2 | 3 | Use `react-redux#connect` instead. This repo will be deleted soon. 4 | 5 | #redux-react-connector 6 | 7 | Connector implementation meant for use with the [redux](https://github.com/gaearon/redux) [flux](https://facebook.github.io/flux/docs/overview.html) implementation. 8 | 9 | ## Why 10 | 11 | #### Already provided from `react-redux#Connector` 12 | 13 | - Encapsulates all store listening and state in one higher-order Component 14 | - Pass all store state as props to your Components 15 | 16 | #### `redux-react-connect` additionally provides 17 | 18 | - Convenient `toStores` select function for easy listenin' to multiple stores by name 19 | - Gets all data from specified stores without additional configuration 20 | - Invisible `Provider` wrapping of Components 21 | 22 | ## Install 23 | 24 | ``` 25 | npm install redux-react-connect --save-dev 26 | ``` 27 | 28 | ## Usage 29 | 30 | As usual, initializing Redux is required. Your `./store.js` might look like this: 31 | 32 | ``` 33 | import { createStore, combineReducers } from 'redux' 34 | import * as reducers from './my-reducer-index' 35 | 36 | export default createStore(combineReducers(reducers)) 37 | ``` 38 | 39 | Now you need to initialize your connector. Your `./connect.js` might look like this: 40 | 41 | ``` 42 | import store from './store' 43 | import { createConnector, toStores } from 'redux-react-connector' 44 | 45 | export default createConnector(store) 46 | ``` 47 | 48 | Now you're all ready to connect your stores' data to components: 49 | 50 | ``` 51 | import { toStores } from 'redux-react-connector' 52 | import connectToStores from './connect' 53 | 54 | @connect(toStores('myReducer')) 55 | class MyComponent extends React.Component { 56 | render() { 57 | return ( 58 |
{this.props.myReducer.reducerProperty}
59 | ) 60 | } 61 | } 62 | ``` 63 | 64 | Using the decorator wraps the Component in a higher-order Component that takes care of store state listening. It will pass the props from the store into your Component as `props`. 65 | 66 | (Note that to use decorators, you'll need something like [babel on stage 1](https://babeljs.io/docs/usage/experimental/). 67 | 68 | In the example above, `myReducer` is the name of your reducer, and on that object all the store's state for that reducer will be available, as shown with `reducerProperty` above. 69 | 70 | To listen to multiple stores, pass, for instance, 'myOtherReducerName' to the decorator. Note that these names match those that you exported in your `./my-reducer-index.js` file and with which you initialized Redux. 71 | 72 | ## Custom Selector 73 | 74 | If you'd rather creator your own select function instead of using the convenient `toStores` function, that's still possible: 75 | 76 | ``` 77 | import connectToStores from './connect' 78 | 79 | @connect(state => { myReducer: state.myReducer }) 80 | class MyComponent extends React.Component { 81 | render() { 82 | return ( 83 |
{this.props.myReducer.reducerProperty}
84 | ) 85 | } 86 | } 87 | ``` 88 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports.toStores = require('./lib/to-stores') 2 | exports.createConnector = require('./lib/create') 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-react-connector", 3 | "version": "0.4.0", 4 | "description": "Higher-order React component for listening to redux stores", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha \"src/**/*.spec.js\"", 8 | "test-watch": "mocha \"src/**/*.spec.js\" --watch", 9 | "compile": "babel src/ --stage 0 --source-maps --debug --out-dir lib/", 10 | "prepublish": "npm run compile" 11 | }, 12 | "keywords": [ 13 | "react", 14 | "redux", 15 | "flux", 16 | "stores", 17 | "functional", 18 | "subscribe" 19 | ], 20 | "author": "jaketrent", 21 | "license": "MIT", 22 | "devDependencies": { 23 | "babel": "^5.6.14", 24 | "jsdom": "^3.1.2", 25 | "mocha": "^2.2.5", 26 | "rf-release": "^0.4.0", 27 | "should": "^7.0.1" 28 | }, 29 | "dependencies": { 30 | "react": "^0.13.3", 31 | "react-redux": "^0.2.2", 32 | "redux": "^1.0.0-rc" 33 | } 34 | } -------------------------------------------------------------------------------- /src/__specs__/create.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react/addons' 2 | import { combineReducers, createStore } from 'redux' 3 | 4 | import createConnector from '../create' 5 | import toStores from '../to-stores' 6 | 7 | const { TestUtils } = React.addons 8 | 9 | function wrappedComponentProps(comp) { 10 | return comp.refs[3].refs[2].refs[1].props // contact! 11 | } 12 | 13 | describe('create', () => { 14 | 15 | const initialState = { 16 | users: { 17 | users: [], 18 | count: 0 19 | }, 20 | plans: { 21 | plans: [{ id: 'abc123' }] 22 | } 23 | } 24 | const reducers = { 25 | users: () => initialState.users, 26 | plans: () => initialState.plans 27 | } 28 | 29 | const store = createStore(combineReducers(reducers)) 30 | const connect = createConnector(store) 31 | 32 | it('lets existing props flow through', () => { 33 | const reducerName = Object.keys(reducers)[0] 34 | @connect(toStores(reducerName)) 35 | class TestComp extends React.Component { 36 | render() { return
Test Comp
} 37 | } 38 | const comp = TestUtils.renderIntoDocument() 39 | wrappedComponentProps(comp).should.have.property('existing') 40 | }) 41 | 42 | it('adds key for store in props', () => { 43 | const reducerName = Object.keys(reducers)[0] 44 | @connect(toStores(reducerName)) 45 | class TestComp extends React.Component { 46 | render() { return
Test Comp
} 47 | } 48 | const comp = TestUtils.renderIntoDocument() 49 | wrappedComponentProps(comp).should.have.property(reducerName) 50 | }) 51 | 52 | it('keys per store in props', () => { 53 | const reducerNames = Object.keys(reducers) 54 | @connect(toStores(...reducerNames)) 55 | class TestComp extends React.Component { 56 | render() { return
Test Comp
} 57 | } 58 | const comp = TestUtils.renderIntoDocument() 59 | reducerNames.forEach(reducerName => { 60 | wrappedComponentProps(comp).should.have.property(reducerName) 61 | }) 62 | }) 63 | 64 | it('transfers all state from the store as props', () => { 65 | const reducerName = 'plans' 66 | @connect(toStores(reducerName)) 67 | class TestComp extends React.Component { 68 | render() { return
Test Comp
} 69 | } 70 | const comp = TestUtils.renderIntoDocument() 71 | wrappedComponentProps(comp)[reducerName].should.eql(initialState[reducerName]) 72 | }) 73 | 74 | }) -------------------------------------------------------------------------------- /src/create.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Connector, Provider } from 'react-redux' 3 | 4 | export default function createConnector(store) { 5 | return function connect(select) { 6 | return function decorateSource(DecoratedComponent) { 7 | return class ConnectorWrapper extends React.Component { 8 | render() { 9 | return ( 10 | 11 | {() => ( 12 | 13 | {(props) => } 14 | 15 | )} 16 | 17 | ) 18 | } 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/to-stores.js: -------------------------------------------------------------------------------- 1 | export default function toStores(...storeNames) { 2 | return state => { 3 | return storeNames.reduce((allStoresState, storeName) => { 4 | return { 5 | ...allStoresState, 6 | [storeName]: state[storeName] 7 | } 8 | }, {}) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require test/utils/babel-register.js 2 | --require test/utils/dom.js 3 | --require test/utils/react-warnings.js 4 | --require should 5 | --reporter nyan -------------------------------------------------------------------------------- /test/utils/babel-register.js: -------------------------------------------------------------------------------- 1 | require('babel/register')({ 2 | stage: 0 3 | }) -------------------------------------------------------------------------------- /test/utils/dom.js: -------------------------------------------------------------------------------- 1 | import jsdom from 'jsdom' 2 | 3 | const doc = jsdom.jsdom('') 4 | const win = doc.defaultView 5 | global.document = doc 6 | global.window = win 7 | propagateToGlobal(win) 8 | 9 | // from mocha-jsdom https://github.com/rstacruz/mocha-jsdom/blob/master/index.js#L80 10 | function propagateToGlobal (window) { 11 | for (let key in window) { 12 | if (!window.hasOwnProperty(key)) continue 13 | if (key in global) continue 14 | 15 | global[key] = window[key] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/utils/react-warnings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fail tests when propType or prop warnings are printed by React 3 | */ 4 | let warn = console.warn 5 | console.warn = function(warning) { 6 | if (/(Invalid prop|Failed propType)/.test(warning)) { 7 | throw new Error(warning) 8 | } 9 | warn.apply(console, arguments) 10 | } --------------------------------------------------------------------------------