Skip to content

Commit

Permalink
Merge pull request #25 from gaearon/new-api
Browse files Browse the repository at this point in the history
New API
  • Loading branch information
gaearon committed Aug 7, 2015
2 parents ae1aaef + 187532c commit a648443
Show file tree
Hide file tree
Showing 16 changed files with 838 additions and 584 deletions.
359 changes: 246 additions & 113 deletions README.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "react-redux",
"version": "0.4.0",
"description": "Redux bindings for React",
"version": "0.5.0",
"description": "React bindings for Redux",
"main": "./lib/index.js",
"scripts": {
"build:lib": "babel src --out-dir lib",
Expand Down Expand Up @@ -60,6 +60,6 @@
"invariant": "^2.0.0"
},
"peerDependencies": {
"redux": "^1.0.0 || 1.0.0-alpha || 1.0.0-rc"
"redux": "^1.0.0 || 1.0.0-rc"
}
}
7 changes: 2 additions & 5 deletions src/components/createAll.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import createProvider from './createProvider';

import createConnector from './createConnector';
import createConnectDecorator from './createConnectDecorator';
import createConnect from './createConnect';

export default function createAll(React) {
const Provider = createProvider(React);
const connect = createConnectDecorator(React, createConnector(React));
const connect = createConnect(React);

// provider and Connector are deprecated and removed from public API
return { Provider, connect };
}
144 changes: 144 additions & 0 deletions src/components/createConnect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import createStoreShape from '../utils/createStoreShape';
import shallowEqualScalar from '../utils/shallowEqualScalar';
import shallowEqual from '../utils/shallowEqual';
import isPlainObject from '../utils/isPlainObject';
import wrapActionCreators from '../utils/wrapActionCreators';
import invariant from 'invariant';

const defaultMapState = () => ({});
const defaultMapDispatch = dispatch => ({ dispatch });
const defaultMergeProps = (stateSlice, actionsCreators, props) => ({
...props,
...stateSlice,
...actionsCreators
});

function getDisplayName(Component) {
return Component.displayName || Component.name || 'Component';
}

export default function createConnect(React) {
const { Component, PropTypes } = React;
const storeShape = createStoreShape(PropTypes);

return function connect(
mapState = defaultMapState,
mapDispatchOrActionCreators = defaultMapDispatch,
mergeProps = defaultMergeProps
) {
const shouldSubscribe = mapState !== defaultMapState;
const mapDispatch = isPlainObject(mapDispatchOrActionCreators) ?
wrapActionCreators(mapDispatchOrActionCreators) :
mapDispatchOrActionCreators;

return DecoratedComponent => class ConnectDecorator extends Component {
static displayName = `Connect(${getDisplayName(DecoratedComponent)})`;
static DecoratedComponent = DecoratedComponent;

static contextTypes = {
store: storeShape.isRequired
};

shouldComponentUpdate(nextProps, nextState) {
return (this.subscribed && !this.isSliceEqual(this.state.slice, nextState.slice)) ||
!shallowEqualScalar(this.props, nextProps);
}

isSliceEqual(slice, nextSlice) {
const isRefEqual = slice === nextSlice;
if (
isRefEqual ||
typeof slice !== 'object' ||
typeof nextSlice !== 'object'
) {
return isRefEqual;
}

return shallowEqual(slice, nextSlice);
}

constructor(props, context) {
super(props, context);
this.setUnderlyingRef = ::this.setUnderlyingRef;
this.state = {
...this.mapState(props, context),
...this.mapDispatch(context)
};
}

componentDidMount() {
if (shouldSubscribe) {
this.subscribed = true;
this.unsubscribe = this.context.store.subscribe(::this.handleChange);
}
}

componentWillUnmount() {
if (shouldSubscribe) {
this.unsubscribe();
}
}

handleChange(props = this.props) {
const nextState = this.mapState(props, this.context);
if (!this.isSliceEqual(this.state.slice, nextState.slice)) {
this.setState(nextState);
}
}

mapState(props = this.props, context = this.context) {
const state = context.store.getState();
const slice = mapState(state);

invariant(
isPlainObject(slice),
'`mapState` must return an object. Instead received %s.',
slice
);

return { slice };
}

mapDispatch(context = this.context) {
const { dispatch } = context.store;
const actionCreators = mapDispatch(dispatch);

invariant(
isPlainObject(actionCreators),
'`mapDispatch` must return an object. Instead received %s.',
actionCreators
);

return { actionCreators };
}

merge(props = this.props, state = this.state) {
const { slice, actionCreators } = state;
const merged = mergeProps(slice, actionCreators, props);

invariant(
isPlainObject(merged),
'`mergeProps` must return an object. Instead received %s.',
merged
);

return merged;
}

getUnderlyingRef() {
return this.underlyingRef;
}

setUnderlyingRef(instance) {
this.underlyingRef = instance;
}

render() {
return (
<DecoratedComponent ref={this.setUnderlyingRef}
{...this.merge()} />
);
}
};
};
}
25 changes: 0 additions & 25 deletions src/components/createConnectDecorator.js

This file was deleted.

89 changes: 0 additions & 89 deletions src/components/createConnector.js

This file was deleted.

1 change: 0 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import createAll from './components/createAll';

// provide and Connector are deprecated and removed from public API
export const { Provider, connect } = createAll(React);
1 change: 0 additions & 1 deletion src/native.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react-native';
import createAll from './components/createAll';

// provide and Connector are deprecated and removed from public API
export const { Provider, connect } = createAll(React);
3 changes: 0 additions & 3 deletions src/utils/getDisplayName.js

This file was deleted.

24 changes: 23 additions & 1 deletion src/utils/isPlainObject.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
const fnToString = (fn) => Function.prototype.toString.call(fn);

/**
* @param {any} obj The object to inspect.
* @returns {boolean} True if the argument appears to be a plain object.
*/
export default function isPlainObject(obj) {
return obj ? typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.prototype : false;
if (!obj || typeof obj !== 'object') {
return false;
}

const proto = typeof obj.constructor === 'function' ?
Object.getPrototypeOf(obj) :
Object.prototype;

if (proto === null) {
return true;
}

const constructor = proto.constructor;

return typeof constructor === 'function'
&& constructor instanceof constructor
&& fnToString(constructor) === fnToString(Object);
}
5 changes: 5 additions & 0 deletions src/utils/wrapActionCreators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { bindActionCreators } from 'redux';

export default function wrapActionCreators(actionCreators) {
return dispatch => bindActionCreators(actionCreators, dispatch);
}
Loading

0 comments on commit a648443

Please sign in to comment.