Skip to content

Commit

Permalink
Drop support for React 0.13
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon committed Oct 15, 2015
1 parent 69de34f commit c54ffd9
Show file tree
Hide file tree
Showing 14 changed files with 324 additions and 506 deletions.
1 change: 0 additions & 1 deletion native.js

This file was deleted.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
"jsdom": "~5.4.3",
"mocha": "^2.2.5",
"mocha-jsdom": "~0.4.0",
"react": "^0.14.0-rc1",
"react-addons-test-utils": "^0.14.0-rc1",
"react-dom": "^0.14.0-rc1",
"react": "^0.14.0",
"react-addons-test-utils": "^0.14.0",
"react-dom": "^0.14.0",
"redux": "^3.0.0",
"rimraf": "^2.3.4",
"webpack": "^1.11.0"
Expand All @@ -62,6 +62,7 @@
"invariant": "^2.0.0"
},
"peerDependencies": {
"react": "^0.14.0",
"redux": "^2.0.0 || ^3.0.0"
}
}
51 changes: 51 additions & 0 deletions src/components/Provider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Component, PropTypes, Children } from 'react';
import storeShape from '../utils/storeShape';

let didWarnAboutReceivingStore = false;
function warnAboutReceivingStore() {
if (didWarnAboutReceivingStore) {
return;
}

didWarnAboutReceivingStore = true;
console.error( // eslint-disable-line no-console
'<Provider> does not support changing `store` on the fly. ' +
'It is most likely that you see this error because you updated to ' +
'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' +
'automatically. See https://github.com/rackt/react-redux/releases/' +
'tag/v2.0.0 for the migration instructions.'
);
}

export default class Provider extends Component {
getChildContext() {
return { store: this.store };
}

constructor(props, context) {
super(props, context);
this.store = props.store;
}

componentWillReceiveProps(nextProps) {
const { store } = this;
const { store: nextStore } = nextProps;

if (store !== nextStore) {
warnAboutReceivingStore();
}
}

render() {
let { children } = this.props;
return Children.only(children);
}
}

Provider.propTypes = {
store: storeShape.isRequired,
children: PropTypes.element.isRequired
};
Provider.childContextTypes = {
store: storeShape.isRequired
};
234 changes: 234 additions & 0 deletions src/components/connect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import React, { Component } from 'react';
import storeShape from '../utils/storeShape';
import shallowEqual from '../utils/shallowEqual';
import isPlainObject from '../utils/isPlainObject';
import wrapActionCreators from '../utils/wrapActionCreators';
import hoistStatics from 'hoist-non-react-statics';
import invariant from 'invariant';

const defaultMapStateToProps = () => ({});
const defaultMapDispatchToProps = dispatch => ({ dispatch });
const defaultMergeProps = (stateProps, dispatchProps, parentProps) => ({
...parentProps,
...stateProps,
...dispatchProps
});

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

// Helps track hot reloading.
let nextVersion = 0;

export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
const shouldSubscribe = Boolean(mapStateToProps);
const finalMapStateToProps = mapStateToProps || defaultMapStateToProps;
const finalMapDispatchToProps = isPlainObject(mapDispatchToProps) ?
wrapActionCreators(mapDispatchToProps) :
mapDispatchToProps || defaultMapDispatchToProps;
const finalMergeProps = mergeProps || defaultMergeProps;
const shouldUpdateStateProps = finalMapStateToProps.length > 1;
const shouldUpdateDispatchProps = finalMapDispatchToProps.length > 1;
const { pure = true } = options;

// Helps track hot reloading.
const version = nextVersion++;

function computeStateProps(store, props) {
const state = store.getState();
const stateProps = shouldUpdateStateProps ?
finalMapStateToProps(state, props) :
finalMapStateToProps(state);

invariant(
isPlainObject(stateProps),
'`mapStateToProps` must return an object. Instead received %s.',
stateProps
);
return stateProps;
}

function computeDispatchProps(store, props) {
const { dispatch } = store;
const dispatchProps = shouldUpdateDispatchProps ?
finalMapDispatchToProps(dispatch, props) :
finalMapDispatchToProps(dispatch);

invariant(
isPlainObject(dispatchProps),
'`mapDispatchToProps` must return an object. Instead received %s.',
dispatchProps
);
return dispatchProps;
}

function computeNextState(stateProps, dispatchProps, parentProps) {
const mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps);
invariant(
isPlainObject(mergedProps),
'`mergeProps` must return an object. Instead received %s.',
mergedProps
);
return mergedProps;
}

return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {

shouldComponentUpdate(nextProps, nextState) {
if (!pure) {
this.updateStateProps(nextProps);
this.updateDispatchProps(nextProps);
this.updateState(nextProps);
return true;
}

const storeChanged = nextState.storeState !== this.state.storeState;
const propsChanged = !shallowEqual(nextProps, this.props);
let mapStateProducedChange = false;
let dispatchPropsChanged = false;

if (storeChanged || (propsChanged && shouldUpdateStateProps)) {
mapStateProducedChange = this.updateStateProps(nextProps);
}

if (propsChanged && shouldUpdateDispatchProps) {
dispatchPropsChanged = this.updateDispatchProps(nextProps);
}

if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps);
return true;
}

return false;
}

constructor(props, context) {
super(props, context);
this.version = version;
this.store = props.store || context.store;

invariant(this.store,
`Could not find "store" in either the context or ` +
`props of "${this.constructor.displayName}". ` +
`Either wrap the root component in a <Provider>, ` +
`or explicitly pass "store" as a prop to "${this.constructor.displayName}".`
);

this.stateProps = computeStateProps(this.store, props);
this.dispatchProps = computeDispatchProps(this.store, props);
this.state = { storeState: null };
this.updateState();
}

computeNextState(props = this.props) {
return computeNextState(
this.stateProps,
this.dispatchProps,
props
);
}

updateStateProps(props = this.props) {
const nextStateProps = computeStateProps(this.store, props);
if (shallowEqual(nextStateProps, this.stateProps)) {
return false;
}

this.stateProps = nextStateProps;
return true;
}

updateDispatchProps(props = this.props) {
const nextDispatchProps = computeDispatchProps(this.store, props);
if (shallowEqual(nextDispatchProps, this.dispatchProps)) {
return false;
}

this.dispatchProps = nextDispatchProps;
return true;
}

updateState(props = this.props) {
this.nextState = this.computeNextState(props);
}

isSubscribed() {
return typeof this.unsubscribe === 'function';
}

trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
this.unsubscribe = this.store.subscribe(::this.handleChange);
this.handleChange();
}
}

tryUnsubscribe() {
if (this.unsubscribe) {
this.unsubscribe();
this.unsubscribe = null;
}
}

componentDidMount() {
this.trySubscribe();
}

componentWillUnmount() {
this.tryUnsubscribe();
}

handleChange() {
if (!this.unsubscribe) {
return;
}

this.setState({
storeState: this.store.getState()
});
}

getWrappedInstance() {
return this.refs.wrappedInstance;
}

render() {
return (
<WrappedComponent ref='wrappedInstance'
{...this.nextState} />
);
}
}

Connect.displayName = `Connect(${getDisplayName(WrappedComponent)})`;
Connect.WrappedComponent = WrappedComponent;
Connect.contextTypes = {
store: storeShape
};
Connect.propTypes = {
store: storeShape
};

if (process.env.NODE_ENV !== 'production') {
Connect.prototype.componentWillUpdate = function componentWillUpdate() {
if (this.version === version) {
return;
}

// We are hot reloading!
this.version = version;

// Update the state and bindings.
this.trySubscribe();
this.updateStateProps();
this.updateDispatchProps();
this.updateState();
};
}

return hoistStatics(Connect, WrappedComponent);
};
}
9 changes: 0 additions & 9 deletions src/components/createAll.js

This file was deleted.

Loading

0 comments on commit c54ffd9

Please sign in to comment.