Skip to content

New API #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Aug 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6ef06e
WIP connectWrapper that will eventually replace connectDecorator and …
gnoff Jul 30, 2015
063777a
intermediate commit. old decorator and connector are still present
gnoff Jul 31, 2015
ce8bf1e
implemented new connect api. takes in selectState, dispatchBinder, me…
gnoff Jul 31, 2015
a788376
forgot to add {...this.props} to DecoratedComponent in render
gnoff Jul 31, 2015
b446894
use ref callback to place instance of underlying component on wrapped…
gnoff Jul 31, 2015
df18c6d
remvoing deprecated code for Connector and original connectDecorator
gnoff Jul 31, 2015
74c3d9d
move props in identityMerge to front to allow override by slice and a…
gnoff Jul 31, 2015
44287dc
merging master
gnoff Jul 31, 2015
80ebc01
Merge pull request #1 from gnoff/underlyingRef
gnoff Jul 31, 2015
170b1b7
changed ConnectDecorator#bindActionCreators to ConnectDecorator#bindD…
Jul 31, 2015
105a2aa
remove test for changing select prop as it no longer applies to new api
Jul 31, 2015
9256e9d
Merge pull request #2 from gaearon/master
gnoff Aug 6, 2015
c54a8b8
fixing test reference to bindActionCreators which was renamed bindDis…
gnoff Aug 6, 2015
1e9809e
Revert deprecation in favor of real PR
gaearon Aug 7, 2015
4a5756e
Merge remote-tracking branch 'gnoff/master' into new-api
gaearon Aug 7, 2015
0949488
Move stuff around, finish removing provide() and <Connector>
gaearon Aug 7, 2015
9992827
Style tweaks
gaearon Aug 7, 2015
47a7df7
Add a test and some style fixes
gaearon Aug 7, 2015
ca47a0a
Dispatch should be passed by default
gaearon Aug 7, 2015
d8d416e
Use better isPlainObject
gaearon Aug 7, 2015
6e99536
Rename arguments
gaearon Aug 7, 2015
3079d00
Update README.md
gaearon Aug 7, 2015
423a590
Update README.md
gaearon Aug 7, 2015
817e710
Update README.md
gaearon Aug 7, 2015
fcbce6f
Update README.md
gaearon Aug 7, 2015
06a060d
Update README.md
gaearon Aug 7, 2015
25946cf
Update README.md
gaearon Aug 7, 2015
65ce197
Update README.md
gaearon Aug 7, 2015
4a3d699
Update README.md
gaearon Aug 7, 2015
9ed8f48
Update README.md
gaearon Aug 7, 2015
95bb962
Update README.md
gaearon Aug 7, 2015
5fdeade
Update README.md
gaearon Aug 7, 2015
ea136fa
Update README.md
gaearon Aug 7, 2015
60eb884
Update README.md
gaearon Aug 7, 2015
187532c
0.5.0
gaearon Aug 7, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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