react-redux
Advanced tools
Comparing version 2.1.2 to 3.0.0-alpha
@@ -231,3 +231,26 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
Connect.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { | ||
return !pure || !_utilsShallowEqual2['default'](this.state.props, nextState.props); | ||
if (!pure) { | ||
this.updateState(nextProps); | ||
return true; | ||
} | ||
var storeChanged = nextState.storeState !== this.state.storeState; | ||
var propsChanged = !_utilsShallowEqual2['default'](nextProps, this.props); | ||
var mapStateProducedChange = false; | ||
var 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; | ||
}; | ||
@@ -268,5 +291,4 @@ | ||
this.dispatchProps = computeDispatchProps(this.store, props); | ||
this.state = { | ||
props: this.computeNextState() | ||
}; | ||
this.state = { storeState: null }; | ||
this.updateState(); | ||
} | ||
@@ -307,8 +329,3 @@ | ||
var nextState = this.computeNextState(props); | ||
if (!_utilsShallowEqual2['default'](nextState, this.state.props)) { | ||
this.setState({ | ||
props: nextState | ||
}); | ||
} | ||
this.nextState = this.computeNextState(props); | ||
}; | ||
@@ -338,16 +355,2 @@ | ||
Connect.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { | ||
if (!_utilsShallowEqual2['default'](nextProps, this.props)) { | ||
if (shouldUpdateStateProps) { | ||
this.updateStateProps(nextProps); | ||
} | ||
if (shouldUpdateDispatchProps) { | ||
this.updateDispatchProps(nextProps); | ||
} | ||
this.updateState(nextProps); | ||
} | ||
}; | ||
Connect.prototype.componentWillUnmount = function componentWillUnmount() { | ||
@@ -362,5 +365,3 @@ this.tryUnsubscribe(); | ||
if (this.updateStateProps()) { | ||
this.updateState(); | ||
} | ||
this.setState({ storeState: this.store.getState() }); | ||
}; | ||
@@ -374,3 +375,3 @@ | ||
return React.createElement(WrappedComponent, _extends({ ref: 'wrappedInstance' | ||
}, this.state.props)); | ||
}, this.nextState)); | ||
}; | ||
@@ -377,0 +378,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react"),require("redux")):"function"==typeof define&&define.amd?define(["react","redux"],e):"object"==typeof exports?exports.ReactRedux=e(require("react"),require("redux")):t.ReactRedux=e(t.React,t.Redux)}(this,function(t,e){return function(t){function e(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}e.__esModule=!0;var o=r(9),u=n(o),s=r(2),i=n(s),a=i.default(u.default),c=a.Provider,p=a.connect;e.Provider=c,e.connect=p},function(t,e){"use strict";function r(t){return t.shape({subscribe:t.func.isRequired,dispatch:t.func.isRequired,getState:t.func.isRequired})}e.__esModule=!0,e.default=r,t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t){var e=s.default(t),r=a.default(t);return{Provider:e,connect:r}}e.__esModule=!0,e.default=o;var u=r(4),s=n(u),i=r(3),a=n(i);t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t){return t.displayName||t.name||"Component"}function i(t){var e=t.Component,r=t.PropTypes,n=f.default(r);return function(r,i,p){function f(t,e){var r=t.getState(),n=S?j(r,e):j(r);return g.default(y.default(n),"`mapStateToProps` must return an object. Instead received %s.",n),n}function l(t,e){var r=t.dispatch,n=C?O(r,e):O(r);return g.default(y.default(n),"`mapDispatchToProps` must return an object. Instead received %s.",n),n}function h(t,e,r){var n=R(t,e,r);return g.default(y.default(n),"`mergeProps` must return an object. Instead received %s.",n),n}var b=arguments.length<=3||void 0===arguments[3]?{}:arguments[3],m=Boolean(r),j=r||x,O=y.default(i)?v.default(i):i||P,R=p||_,S=j.length>1,C=O.length>1,M=b.pure,T=void 0===M?!0:M,k=w++;return function(r){var i=function(e){function i(t,r){o(this,i),e.call(this,t,r),this.version=k,this.store=t.store||r.store,g.default(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=f(this.store,t),this.dispatchProps=l(this.store,t),this.state={props:this.computeNextState()}}return u(i,e),i.prototype.shouldComponentUpdate=function(t,e){return!T||!d.default(this.state.props,e.props)},a(i,null,[{key:"displayName",value:"Connect("+s(r)+")",enumerable:!0},{key:"WrappedComponent",value:r,enumerable:!0},{key:"contextTypes",value:{store:n},enumerable:!0},{key:"propTypes",value:{store:n},enumerable:!0}]),i.prototype.computeNextState=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0];return h(this.stateProps,this.dispatchProps,t)},i.prototype.updateStateProps=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=f(this.store,t);return d.default(e,this.stateProps)?!1:(this.stateProps=e,!0)},i.prototype.updateDispatchProps=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=l(this.store,t);return d.default(e,this.dispatchProps)?!1:(this.dispatchProps=e,!0)},i.prototype.updateState=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=this.computeNextState(t);d.default(e,this.state.props)||this.setState({props:e})},i.prototype.isSubscribed=function(){return"function"==typeof this.unsubscribe},i.prototype.trySubscribe=function(){m&&!this.unsubscribe&&(this.unsubscribe=this.store.subscribe(this.handleChange.bind(this)),this.handleChange())},i.prototype.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null)},i.prototype.componentDidMount=function(){this.trySubscribe()},i.prototype.componentWillReceiveProps=function(t){d.default(t,this.props)||(S&&this.updateStateProps(t),C&&this.updateDispatchProps(t),this.updateState(t))},i.prototype.componentWillUnmount=function(){this.tryUnsubscribe()},i.prototype.handleChange=function(){this.unsubscribe&&this.updateStateProps()&&this.updateState()},i.prototype.getWrappedInstance=function(){return this.refs.wrappedInstance},i.prototype.render=function(){return t.createElement(r,c({ref:"wrappedInstance"},this.state.props))},i}(e);return i}}}e.__esModule=!0;var a=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),c=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t};e.default=i;var p=r(1),f=n(p),l=r(6),d=n(l),h=r(5),y=n(h),b=r(7),v=n(b),m=r(8),g=n(m),x=function(){return{}},P=function(t){return{dispatch:t}},_=function(t,e,r){return c({},r,t,e)},w=0;t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t){var e=t.version;if("string"!=typeof e)return!0;var r=e.split("."),n=parseInt(r[0],10),o=parseInt(r[1],10);return 0===n&&13===o}function i(t){function e(){h||d||(h=!0,console.error("With React 0.14 and later versions, you no longer need to wrap <Provider> child into a function."))}function r(){!h&&d&&(h=!0,console.error("With React 0.13, you need to wrap <Provider> child into a function. This restriction will be removed with React 0.14."))}function n(){y||(y=!0,console.error("<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."))}var i=t.Component,c=t.PropTypes,f=t.Children,l=p.default(c),d=s(t),h=!1,y=!1;return function(t){function s(e,r){o(this,s),t.call(this,e,r),this.store=e.store}return u(s,t),s.prototype.getChildContext=function(){return{store:this.store}},a(s,null,[{key:"childContextTypes",value:{store:l.isRequired},enumerable:!0},{key:"propTypes",value:{store:l.isRequired,children:(d?c.func:c.element).isRequired},enumerable:!0}]),s.prototype.componentWillReceiveProps=function(t){var e=this.store,r=t.store;e!==r&&n()},s.prototype.render=function(){var t=this.props.children;return"function"==typeof t?(e(),t=t()):r(),f.only(t)},s}(i)}e.__esModule=!0;var a=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.default=i;var c=r(1),p=n(c);t.exports=e.default},function(t,e){"use strict";function r(t){if(!t||"object"!=typeof t)return!1;var e="function"==typeof t.constructor?Object.getPrototypeOf(t):Object.prototype;if(null===e)return!0;var r=e.constructor;return"function"==typeof r&&r instanceof r&&n(r)===n(Object)}e.__esModule=!0,e.default=r;var n=function(t){return Function.prototype.toString.call(t)};t.exports=e.default},function(t,e){"use strict";function r(t,e){if(t===e)return!0;var r=Object.keys(t),n=Object.keys(e);if(r.length!==n.length)return!1;for(var o=Object.prototype.hasOwnProperty,u=0;u<r.length;u++)if(!o.call(e,r[u])||t[r[u]]!==e[r[u]])return!1;return!0}e.__esModule=!0,e.default=r,t.exports=e.default},function(t,e,r){"use strict";function n(t){return function(e){return o.bindActionCreators(t,e)}}e.__esModule=!0,e.default=n;var o=r(10);t.exports=e.default},function(t,e,r){"use strict";var n=function(t,e,r,n,o,u,s,i){if(!t){var a;if(void 0===e)a=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[r,n,o,u,s,i],p=0;a=new Error("Invariant Violation: "+e.replace(/%s/g,function(){return c[p++]}))}throw a.framesToPop=1,a}};t.exports=n},function(e,r){e.exports=t},function(t,r){t.exports=e}])}); | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react"),require("redux")):"function"==typeof define&&define.amd?define(["react","redux"],e):"object"==typeof exports?exports.ReactRedux=e(require("react"),require("redux")):t.ReactRedux=e(t.React,t.Redux)}(this,function(t,e){return function(t){function e(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}e.__esModule=!0;var o=r(9),u=n(o),i=r(2),s=n(i),a=s.default(u.default),c=a.Provider,p=a.connect;e.Provider=c,e.connect=p},function(t,e){"use strict";function r(t){return t.shape({subscribe:t.func.isRequired,dispatch:t.func.isRequired,getState:t.func.isRequired})}e.__esModule=!0,e.default=r,t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t){var e=i.default(t),r=a.default(t);return{Provider:e,connect:r}}e.__esModule=!0,e.default=o;var u=r(4),i=n(u),s=r(3),a=n(s);t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function i(t){return t.displayName||t.name||"Component"}function s(t){var e=t.Component,r=t.PropTypes,n=f.default(r);return function(r,s,p){function f(t,e){var r=t.getState(),n=R?S(r,e):S(r);return g.default(y.default(n),"`mapStateToProps` must return an object. Instead received %s.",n),n}function l(t,e){var r=t.dispatch,n=C?j(r,e):j(r);return g.default(y.default(n),"`mapDispatchToProps` must return an object. Instead received %s.",n),n}function h(t,e,r){var n=O(t,e,r);return g.default(y.default(n),"`mergeProps` must return an object. Instead received %s.",n),n}var b=arguments.length<=3||void 0===arguments[3]?{}:arguments[3],m=Boolean(r),S=r||x,j=y.default(s)?v.default(s):s||P,O=p||_,R=S.length>1,C=j.length>1,M=b.pure,T=void 0===M?!0:M,k=w++;return function(r){var s=function(e){function s(t,r){o(this,s),e.call(this,t,r),this.version=k,this.store=t.store||r.store,g.default(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=f(this.store,t),this.dispatchProps=l(this.store,t),this.state={storeState:null},this.updateState()}return u(s,e),s.prototype.shouldComponentUpdate=function(t,e){if(!T)return this.updateState(t),!0;var r=e.storeState!==this.state.storeState,n=!d.default(t,this.props),o=!1,u=!1;return(r||n&&R)&&(o=this.updateStateProps(t)),n&&C&&(u=this.updateDispatchProps(t)),n||o||u?(this.updateState(t),!0):!1},a(s,null,[{key:"displayName",value:"Connect("+i(r)+")",enumerable:!0},{key:"WrappedComponent",value:r,enumerable:!0},{key:"contextTypes",value:{store:n},enumerable:!0},{key:"propTypes",value:{store:n},enumerable:!0}]),s.prototype.computeNextState=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0];return h(this.stateProps,this.dispatchProps,t)},s.prototype.updateStateProps=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=f(this.store,t);return d.default(e,this.stateProps)?!1:(this.stateProps=e,!0)},s.prototype.updateDispatchProps=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=l(this.store,t);return d.default(e,this.dispatchProps)?!1:(this.dispatchProps=e,!0)},s.prototype.updateState=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0];this.nextState=this.computeNextState(t)},s.prototype.isSubscribed=function(){return"function"==typeof this.unsubscribe},s.prototype.trySubscribe=function(){m&&!this.unsubscribe&&(this.unsubscribe=this.store.subscribe(this.handleChange.bind(this)),this.handleChange())},s.prototype.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null)},s.prototype.componentDidMount=function(){this.trySubscribe()},s.prototype.componentWillUnmount=function(){this.tryUnsubscribe()},s.prototype.handleChange=function(){this.unsubscribe&&this.setState({storeState:this.store.getState()})},s.prototype.getWrappedInstance=function(){return this.refs.wrappedInstance},s.prototype.render=function(){return t.createElement(r,c({ref:"wrappedInstance"},this.nextState))},s}(e);return s}}}e.__esModule=!0;var a=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),c=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t};e.default=s;var p=r(1),f=n(p),l=r(6),d=n(l),h=r(5),y=n(h),b=r(7),v=n(b),m=r(8),g=n(m),x=function(){return{}},P=function(t){return{dispatch:t}},_=function(t,e,r){return c({},r,t,e)},w=0;t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function i(t){var e=t.version;if("string"!=typeof e)return!0;var r=e.split("."),n=parseInt(r[0],10),o=parseInt(r[1],10);return 0===n&&13===o}function s(t){function e(){h||d||(h=!0,console.error("With React 0.14 and later versions, you no longer need to wrap <Provider> child into a function."))}function r(){!h&&d&&(h=!0,console.error("With React 0.13, you need to wrap <Provider> child into a function. This restriction will be removed with React 0.14."))}function n(){y||(y=!0,console.error("<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."))}var s=t.Component,c=t.PropTypes,f=t.Children,l=p.default(c),d=i(t),h=!1,y=!1;return function(t){function i(e,r){o(this,i),t.call(this,e,r),this.store=e.store}return u(i,t),i.prototype.getChildContext=function(){return{store:this.store}},a(i,null,[{key:"childContextTypes",value:{store:l.isRequired},enumerable:!0},{key:"propTypes",value:{store:l.isRequired,children:(d?c.func:c.element).isRequired},enumerable:!0}]),i.prototype.componentWillReceiveProps=function(t){var e=this.store,r=t.store;e!==r&&n()},i.prototype.render=function(){var t=this.props.children;return"function"==typeof t?(e(),t=t()):r(),f.only(t)},i}(s)}e.__esModule=!0;var a=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.default=s;var c=r(1),p=n(c);t.exports=e.default},function(t,e){"use strict";function r(t){if(!t||"object"!=typeof t)return!1;var e="function"==typeof t.constructor?Object.getPrototypeOf(t):Object.prototype;if(null===e)return!0;var r=e.constructor;return"function"==typeof r&&r instanceof r&&n(r)===n(Object)}e.__esModule=!0,e.default=r;var n=function(t){return Function.prototype.toString.call(t)};t.exports=e.default},function(t,e){"use strict";function r(t,e){if(t===e)return!0;var r=Object.keys(t),n=Object.keys(e);if(r.length!==n.length)return!1;for(var o=Object.prototype.hasOwnProperty,u=0;u<r.length;u++)if(!o.call(e,r[u])||t[r[u]]!==e[r[u]])return!1;return!0}e.__esModule=!0,e.default=r,t.exports=e.default},function(t,e,r){"use strict";function n(t){return function(e){return o.bindActionCreators(t,e)}}e.__esModule=!0,e.default=n;var o=r(10);t.exports=e.default},function(t,e,r){"use strict";var n=function(t,e,r,n,o,u,i,s){if(!t){var a;if(void 0===e)a=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[r,n,o,u,i,s],p=0;a=new Error("Invariant Violation: "+e.replace(/%s/g,function(){return c[p++]}))}throw a.framesToPop=1,a}};t.exports=n},function(e,r){e.exports=t},function(t,r){t.exports=e}])}); |
@@ -103,3 +103,26 @@ 'use strict'; | ||
Connect.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { | ||
return !pure || !_utilsShallowEqual2['default'](this.state.props, nextState.props); | ||
if (!pure) { | ||
this.updateState(nextProps); | ||
return true; | ||
} | ||
var storeChanged = nextState.storeState !== this.state.storeState; | ||
var propsChanged = !_utilsShallowEqual2['default'](nextProps, this.props); | ||
var mapStateProducedChange = false; | ||
var 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; | ||
}; | ||
@@ -140,5 +163,4 @@ | ||
this.dispatchProps = computeDispatchProps(this.store, props); | ||
this.state = { | ||
props: this.computeNextState() | ||
}; | ||
this.state = { storeState: null }; | ||
this.updateState(); | ||
} | ||
@@ -179,8 +201,3 @@ | ||
var nextState = this.computeNextState(props); | ||
if (!_utilsShallowEqual2['default'](nextState, this.state.props)) { | ||
this.setState({ | ||
props: nextState | ||
}); | ||
} | ||
this.nextState = this.computeNextState(props); | ||
}; | ||
@@ -210,16 +227,2 @@ | ||
Connect.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { | ||
if (!_utilsShallowEqual2['default'](nextProps, this.props)) { | ||
if (shouldUpdateStateProps) { | ||
this.updateStateProps(nextProps); | ||
} | ||
if (shouldUpdateDispatchProps) { | ||
this.updateDispatchProps(nextProps); | ||
} | ||
this.updateState(nextProps); | ||
} | ||
}; | ||
Connect.prototype.componentWillUnmount = function componentWillUnmount() { | ||
@@ -234,5 +237,3 @@ this.tryUnsubscribe(); | ||
if (this.updateStateProps()) { | ||
this.updateState(); | ||
} | ||
this.setState({ storeState: this.store.getState() }); | ||
}; | ||
@@ -246,3 +247,3 @@ | ||
return React.createElement(WrappedComponent, _extends({ ref: 'wrappedInstance' | ||
}, this.state.props)); | ||
}, this.nextState)); | ||
}; | ||
@@ -249,0 +250,0 @@ |
{ | ||
"name": "react-redux", | ||
"version": "2.1.2", | ||
"version": "3.0.0-alpha", | ||
"description": "Official React bindings for Redux", | ||
@@ -53,5 +53,5 @@ "main": "./lib/index.js", | ||
"mocha-jsdom": "~0.4.0", | ||
"react": "^0.14.0-beta3", | ||
"react-addons-test-utils": "^0.14.0-beta3", | ||
"react-dom": "^0.14.0-beta3", | ||
"react": "^0.14.0-rc1", | ||
"react-addons-test-utils": "^0.14.0-rc1", | ||
"react-dom": "^0.14.0-rc1", | ||
"redux": "^3.0.0", | ||
@@ -58,0 +58,0 @@ "rimraf": "^2.3.4", |
484
README.md
@@ -11,13 +11,3 @@ React Redux | ||
## Table of Contents | ||
- [Installation](#installation) | ||
- [React Native](#react-native) | ||
- [Quick Start](#quick-start) | ||
- [API](#api) | ||
- [`<Provider store>`](#provider-store) | ||
- [`connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) | ||
- [Troubleshooting](#troubleshooting) | ||
- [License](#license) | ||
## Installation | ||
@@ -36,474 +26,12 @@ | ||
## Quick Start | ||
## Documentation | ||
React bindings for Redux embrace the idea of [dividing “smart” and “dumb” components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0). | ||
- [Quick Start](docs/quick-start.md#quick-start) | ||
- [API](docs/api.md#api) | ||
- [`<Provider store>`](docs/api.md#provider-store) | ||
- [`connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])`](docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) | ||
- [Troubleshooting](docs/troubleshooting.md#troubleshooting) | ||
It is advisable that only top-level components of your app (such as route handlers, for example) are aware of Redux. Components below them should be “dumb” and receive all data via props. | ||
<table> | ||
<thead> | ||
<tr> | ||
<th></th> | ||
<th scope="col" style="text-align:left">“Smart” Components</th> | ||
<th scope="col" style="text-align:left">“Dumb” Components</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<th scope="row" style="text-align:right">Location</th> | ||
<td>Top level, route handlers</td> | ||
<td>Middle and leaf components</td> | ||
</tr> | ||
<tr> | ||
<th scope="row" style="text-align:right">Aware of Redux</th> | ||
<td>Yes</th> | ||
<td>No</th> | ||
</tr> | ||
<tr> | ||
<th scope="row" style="text-align:right">To read data</th> | ||
<td>Subscribe to Redux state</td> | ||
<td>Read data from props</td> | ||
</tr> | ||
<tr> | ||
<th scope="row" style="text-align:right">To change data</th> | ||
<td>Dispatch Redux actions</td> | ||
<td>Invoke callbacks from props</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
### “Dumb” components are unaware of Redux | ||
Let’s say we have a `<Counter />` “dumb” component with a number `value` prop, and an `onIncrement` function prop that it will call when user presses an “Increment” button: | ||
```js | ||
import { Component } from 'react'; | ||
export default class Counter extends Component { | ||
render() { | ||
return ( | ||
<button onClick={this.props.onIncrement}> | ||
{this.props.value} | ||
</button> | ||
); | ||
} | ||
} | ||
``` | ||
### “Smart” components are `connect()`-ed to Redux | ||
Here’s how we hook it up to the Redux Store. | ||
We will use the `connect()` function provided by `react-redux` to turn a “dumb” `Counter` into a smart component. The `connect()` function lets you specify *which exact* state from the Redux store your component wants to track. This lets you subscribe on any level of granularity. | ||
##### `containers/CounterContainer.js` | ||
```js | ||
import { Component } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import Counter from '../components/Counter'; | ||
import { increment } from '../actionsCreators'; | ||
// Which part of the Redux global state does our component want to receive as props? | ||
function mapStateToProps(state) { | ||
return { | ||
value: state.counter | ||
}; | ||
} | ||
// Which action creators does it want to receive by props? | ||
function mapDispatchToProps(dispatch) { | ||
return { | ||
onIncrement: () => dispatch(increment()) | ||
}; | ||
} | ||
export default connect( | ||
mapStateToProps, | ||
mapDispatchToProps | ||
)(Counter); | ||
// You can also pass an object instead of defining `mapDispatchToProps`: | ||
// export default connect(mapStateToProps, CounterActionCreators)(Counter); | ||
// Or you can pass `dispatch` down as a prop if you omit `mapDispatchToProps`: | ||
// export default connect(mapStateToProps)(Counter); | ||
// See more recipes in detailed connect() examples below. | ||
``` | ||
Whether to put the `connect()` call in the same file as the “dumb” component, or separately, is up to you. | ||
Ask yourself whether you’d want to reuse this component but bind it to different data, or not. | ||
### Nesting | ||
You can have many `connect()`-ed components in your app at any depth, and you can even nest them. It is, however, preferable that you try to only `connect()` top-level components such as route handlers, so the data flow in your application stays predictable. | ||
### Support for Decorators | ||
You might have noticed that we used parens twice when calling `connect()`. This is called partial application, and it lets people | ||
use ES7’s proposed decorator syntax: | ||
```js | ||
// Unstable syntax! It might change or break in production. | ||
@connect(mapStateToProps) | ||
export default class CounterContainer { ... } | ||
``` | ||
Don’t forget decorators are experimental! They desugar to function calls anyway as the example above demonstrates. | ||
### Additional Flexibility | ||
This is the most basic usage, but `connect()` supports many other patterns: just passing the vanilla `dispatch()` function down, binding multiple action creators, passing them in an `actions` prop, selecting parts of state and binding action creators depending on `props`, and so on. Check out the `connect()` docs below to learn more. | ||
### Injecting Redux Store | ||
Finally, how do we actually hook it up to the Redux store? We need to create the store somewhere at the root of our component hierarchy. For client apps, the root component is a good place. For server rendering, you can do this in the request handler. | ||
The trick is to wrap the whole view hierarchy into a `<Provider>{() => ... }</Provider>` where `Provider` is imported from `react-redux`. One gotcha is that **the child of `Provider` must be a function**. This is to work around an issue about how context (undocumented feature we have to rely on to pass Redux data to components below) works in React 0.13. In React 0.14, you will be able to put your view hierarchy in `<Provider>` without wrapping it into a function. | ||
```js | ||
import { Component } from 'react'; | ||
import { Provider } from 'react-redux'; | ||
class App extends Component { | ||
render() { | ||
// ... | ||
} | ||
} | ||
const targetEl = document.getElementById('root'); | ||
React.render(( | ||
<Provider store={store}> | ||
{() => <App />} | ||
</Provider> | ||
), targetEl); | ||
``` | ||
## API | ||
### `<Provider store>` | ||
Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping the root component in `<Provider>`. (If you *really* need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use `<Provider>`.) | ||
#### Props | ||
* `store`: (*[Redux Store](http://gaearon.github.io/redux/docs/api/Store.html)*): The single Redux store in your application. | ||
* `children`: (*Function*): Unlike most React components, `<Provider>` accepts a [function as a child](#child-must-be-a-function) with your root component. This is a temporary workaround for a React 0.13 context issue, which will be fixed when React 0.14 comes out. | ||
#### Example | ||
##### Vanilla React | ||
```js | ||
React.render( | ||
<Provider store={store}> | ||
{() => <MyRootComponent />} | ||
</Provider>, | ||
rootEl | ||
); | ||
``` | ||
##### React Router 0.13 | ||
```js | ||
Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { // note "routerState" here | ||
React.render( | ||
<Provider store={store}> | ||
{() => <Handler routerState={routerState} />} // note "routerState" here: important to pass it down | ||
</Provider>, | ||
document.getElementById('root') | ||
); | ||
}); | ||
``` | ||
##### React Router 1.0 | ||
```js | ||
React.render( | ||
<Provider store={store}> | ||
{() => <Router history={history}>...</Router>} | ||
</Provider>, | ||
targetEl | ||
); | ||
``` | ||
### `connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])` | ||
Connects a React component to a Redux store. | ||
It does not modify the component class passed to it. | ||
Instead, it *returns* a new, connected component class, for you to use. | ||
#### Arguments | ||
* [`mapStateToProps(state, [ownProps]): stateProps`] \(*Function*): If specified, the component will subscribe to Redux store updates. Any time it updates, `mapStateToProps` will be called. Its result must be a plain object, and it will be merged into the component’s props. If you omit it, the component will not be subscribed to the Redux store. If `ownProps` is specified as a second argument, then `mapStateToProps` will be re-invoked whenever the component receives new props. | ||
* [`mapDispatchToProps(dispatch, [ownProps]): dispatchProps`] \(*Object* or *Function*): If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but bound to a Redux store, will be merged into the component’s props. If a function is passed, it will be given `dispatch`. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](http://gaearon.github.io/redux/docs/api/bindActionCreators.html) helper from Redux.) If you omit it, the default implementation just injects `dispatch` into your component’s props. If `ownProps` is specified as a second argument, then `mapDispatchToProps` will be re-invoked whenever the component receives new props. | ||
* [`mergeProps(stateProps, dispatchProps, ownProps): props`] \(*Function*): If specified, it is passed the result of `mapStateToProps()`, `mapDispatchToProps()`, and the parent `props`. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, `Object.assign({}, ownProps, stateProps, dispatchProps)` is used by default. | ||
* [`options`] *(Object)* If specified, further customizes the behavior of the connector. | ||
* [`pure`] *(Boolean)*: If true, implements `shouldComponentUpdate` and shallowly compares the result of `mergeProps`, preventing unnecessary updates, assuming that the component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. *Defaults to `true`.* | ||
#### Returns | ||
A React component class that injects state and action creators into your component according to the specified options. | ||
#### Remarks | ||
* It needs to be invoked two times. The first time with its arguments described above, and a second time, with the component: `connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)`. | ||
* It does not modify the passed React component. It returns a new, connected component, that you should use instead. | ||
* The `mapStateToProps` function takes a single argument of the entire Redux store’s state and returns an object to be passed as props. It is often called a **selector**. Use [reselect](https://github.com/faassen/reselect) to efficiently compose selectors and [compute derived data](http://gaearon.github.io/redux/docs/recipes/ComputingDerivedData.html). | ||
* **To use `connect()`, the root component of your app must be wrapped into `<Provider>{() => ... }</Provider>` before being rendered.** You may also pass `store` as a prop to the `connect()`ed component, but it's not recommended, because it's just too much trouble. Only do this for non-fully-React codebases or to stub the store in a unit test. | ||
#### Examples | ||
##### Inject just `dispatch` and don't listen to store | ||
```js | ||
export default connect()(TodoApp); | ||
``` | ||
##### Inject `dispatch` and every field in the global state | ||
>Don’t do this! It kills any performance optimisations because `TodoApp` will rerender after every action. | ||
>It’s better to have more granular `connect()` on several components in your view hierarchy that each only | ||
>listen to a relevant slice of the state. | ||
```js | ||
export default connect(state => state)(TodoApp); | ||
``` | ||
##### Inject `dispatch` and `todos` | ||
```js | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
export default connect(mapStateToProps)(TodoApp); | ||
``` | ||
##### Inject `todos` and all action creators (`addTodo`, `completeTodo`, ...) | ||
```js | ||
import * as actionCreators from './actionCreators'; | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
export default connect(mapStateToProps, actionCreators)(TodoApp); | ||
``` | ||
##### Inject `todos` and all action creators (`addTodo`, `completeTodo`, ...) as `actions` | ||
```js | ||
import * as actionCreators from './actionCreators'; | ||
import { bindActionCreators } from 'redux'; | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
function mapDispatchToProps(dispatch) { | ||
return { actions: bindActionCreators(actionCreators, dispatch) }; | ||
} | ||
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); | ||
``` | ||
##### Inject `todos` and a specific action creator (`addTodo`) | ||
```js | ||
import { addTodo } from './actionCreators'; | ||
import { bindActionCreators } from 'redux'; | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
function mapDispatchToProps(dispatch) { | ||
return bindActionCreators({ addTodo }, dispatch); | ||
} | ||
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); | ||
``` | ||
##### Inject `todos`, todoActionCreators as `todoActions`, and counterActionCreators as `counterActions` | ||
```js | ||
import * as todoActionCreators from './todoActionCreators'; | ||
import * as counterActionCreators from './counterActionCreators'; | ||
import { bindActionCreators } from 'redux'; | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
function mapDispatchToProps(dispatch) { | ||
return { | ||
todoActions: bindActionCreators(todoActionCreators, dispatch), | ||
counterActions: bindActionCreators(counterActionCreators, dispatch) | ||
}; | ||
} | ||
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); | ||
``` | ||
##### Inject `todos`, and todoActionCreators and counterActionCreators together as `actions` | ||
```js | ||
import * as todoActionCreators from './todoActionCreators'; | ||
import * as counterActionCreators from './counterActionCreators'; | ||
import { bindActionCreators } from 'redux'; | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
function mapDispatchToProps(dispatch) { | ||
return { | ||
actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) | ||
}; | ||
} | ||
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); | ||
``` | ||
##### Inject `todos`, and all todoActionCreators and counterActionCreators directly as props | ||
```js | ||
import * as todoActionCreators from './todoActionCreators'; | ||
import * as counterActionCreators from './counterActionCreators'; | ||
import { bindActionCreators } from 'redux'; | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
function mapDispatchToProps(dispatch) { | ||
return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch); | ||
} | ||
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); | ||
``` | ||
##### Inject `todos` of a specific user depending on props | ||
```js | ||
import * as actionCreators from './actionCreators'; | ||
function mapStateToProps(state, ownProps) { | ||
return { todos: state.todos[ownProps.userId] }; | ||
} | ||
export default connect(mapStateToProps)(TodoApp); | ||
``` | ||
##### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action | ||
```js | ||
import * as actionCreators from './actionCreators'; | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
function mergeProps(stateProps, dispatchProps, ownProps) { | ||
return Object.assign({}, ownProps, { | ||
todos: stateProps.todos[ownProps.userId], | ||
addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text) | ||
}); | ||
} | ||
export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp); | ||
``` | ||
## Troubleshooting | ||
Make sure to check out [Troubleshooting Redux](http://gaearon.github.io/redux/docs/Troubleshooting.html) first. | ||
### My views aren’t updating! | ||
See the link above. | ||
In short, | ||
* Reducers should never mutate state, they must return new objects, or React Redux won’t see the updates. | ||
* Make sure you either bind action creators with the `mapDispatchToProps` argument to `connect()` or with the `bindActionCreators()` method, or that you manually call `dispatch()`. Just calling your `MyActionCreators.addTodo()` function won’t work because it just *returns* an action, but does not *dispatch* it. | ||
### My views aren’t updating on route change with React Router 0.13 | ||
If you’re using React Router 0.13, you might [bump into this problem](https://github.com/gaearon/react-redux/issues/43). The solution is simple: whenever you use `<RouteHandler>` or the `Handler` provided by `Router.run`, pass the router state to it. | ||
Root view: | ||
```js | ||
Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { // note "routerState" here | ||
React.render( | ||
<Provider store={store}> | ||
{() => <Handler routerState={routerState} />} // note "routerState" here | ||
</Provider>, | ||
document.getElementById('root') | ||
); | ||
}); | ||
``` | ||
Nested view: | ||
```js | ||
render() { | ||
// Keep passing it down | ||
return <RouteHandler routerState={this.props.routerState} />; | ||
} | ||
``` | ||
Conveniently, this gives your components access to the router state! | ||
You can also upgrade to React Router 1.0 which shouldn’t have this problem. (Let us know if it does!) | ||
### My views aren’t updating when something changes outside of Redux | ||
If your views depend on global state or [React “context”](www.youtube.com/watch?v=H7vlH-wntD4), you might find that views decorated with `connect()` will fail to update. | ||
>This is because `connect()` implements [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate) by default, assuming that your component will produce the same results given the same props and state. This is a similar concept to React’s [PureRenderMixin](https://facebook.github.io/react/docs/pure-render-mixin.html). | ||
The _best_ solution to this is to make sure that your components are pure and pass any external state to them via props. This will ensure that your views do not re-render unless they actually need to re-render and will greatly speed up your application. | ||
If that's not practical for whatever reason (for example, if you’re using a library that depends heavily on React context), you may pass the `pure: false` option to `connect()`: | ||
``` | ||
function mapStateToProps(state) { | ||
return { todos: state.todos }; | ||
} | ||
export default connect(mapStateToProps, null, null, { | ||
pure: false | ||
})(TodoApp); | ||
``` | ||
This will remove the assumption that `TodoApp` is pure and cause it to update whenever its parent component renders. Note that this will make your application less performant, so only do this if you have no other option. | ||
### Could not find "store" in either the context or props | ||
If you have context issues, | ||
1. [Make sure you don’t have a duplicate instance of React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375) on the page. | ||
2. Make sure you didn’t forget to wrap your root component in [`<Provider>`](#provider-store). | ||
3. If you use React Router, something like `<Provider>{() => router}</Provider>` won’t work. Due to the way context works in React 0.13, it’s important that the `<Provider>` children are *created* inside that function. Just referencing an outside variable doesn’t do the trick. Instead of `<Provider>{() => router}</Provider>`, write `<Provider>{() => createRouter()}</Provider>` where `createRouter()` is a function that actually *creates* (and returns) the router. | ||
### Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you’re trying to add a ref to a component that doesn’t have an owner | ||
If you’re using React for web, this usually means you have a [duplicate React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375). Follow the linked instructions to fix this. | ||
If you’re using React Native, make sure you’re importing `react-redux/native` both for `<Provider>` and any `connect()` call. Importing from `react-redux` will not work on React Native. | ||
## License | ||
MIT |
@@ -1059,11 +1059,10 @@ import expect from 'expect'; | ||
const Decorated = decorator(Container); | ||
const expectedError = | ||
`Invariant Violation: Could not find "store" in either the context ` + | ||
`or props of "Connect(Container)". Either wrap the root component in a ` + | ||
`<Provider>, or explicitly pass "store" as a prop to "Connect(Container)".`; | ||
expect(() => TestUtils.renderIntoDocument(<Decorated />)).toThrow(e => { | ||
expect(e.message).toEqual(expectedError); | ||
return true; | ||
}); | ||
expect(() => | ||
TestUtils.renderIntoDocument(<Decorated />) | ||
).toThrow( | ||
'Invariant Violation: Could not find "store" in either the context ' + | ||
'or props of "Connect(Container)". Either wrap the root component in a ' + | ||
'<Provider>, or explicitly pass "store" as a prop to "Connect(Container)".' | ||
); | ||
}); | ||
@@ -1152,3 +1151,101 @@ | ||
}); | ||
it('should pass state consistently to mapState', () => { | ||
const store = createStore(stringBuilder); | ||
store.dispatch({ type: 'APPEND', body: 'a'}); | ||
let childMapStateInvokes = 0; | ||
@connect(state => ({ state })) | ||
class Container extends Component { | ||
emitChange() { | ||
store.dispatch({ type: 'APPEND', body: 'b'}); | ||
} | ||
render() { | ||
return ( | ||
<div> | ||
<button ref="button" onClick={this.emitChange.bind(this)}>change</button> | ||
<ChildContainer parentState={this.props.state} /> | ||
</div> | ||
); | ||
} | ||
} | ||
@connect((state, parentProps) => { | ||
childMapStateInvokes++; | ||
// The state from parent props should always be consistent with the current state | ||
expect(state).toEqual(parentProps.parentState); | ||
return {}; | ||
}) | ||
class ChildContainer extends Component { | ||
render() { | ||
return <Passthrough {...this.props}/>; | ||
} | ||
} | ||
const tree = TestUtils.renderIntoDocument( | ||
<ProviderMock store={store}> | ||
<Container /> | ||
</ProviderMock> | ||
); | ||
expect(childMapStateInvokes).toBe(2); | ||
// The store state stays consistent when setState calls are batched | ||
ReactDOM.unstable_batchedUpdates(() => { | ||
store.dispatch({ type: 'APPEND', body: 'c'}); | ||
}); | ||
expect(childMapStateInvokes).toBe(3); | ||
// setState calls DOM handlers are batched | ||
const container = TestUtils.findRenderedComponentWithType(tree, Container); | ||
const node = React.findDOMNode(container.getWrappedInstance().refs.button); | ||
TestUtils.Simulate.click(node); | ||
expect(childMapStateInvokes).toBe(4); | ||
// In future all setState calls will be batched[1]. Uncomment when it | ||
// happens. For now redux-batched-updates middleware can be used as | ||
// workaround this. | ||
// | ||
// [1]: https://twitter.com/sebmarkbage/status/642366976824864768 | ||
// | ||
// store.dispatch({ type: 'APPEND', body: 'd'}); | ||
// expect(childMapStateInvokes).toBe(5); | ||
}); | ||
it('should not render the wrapped component when mapState does not produce change', () => { | ||
const store = createStore(stringBuilder); | ||
let renderCalls = 0; | ||
let mapStateCalls = 0; | ||
@connect(() => { | ||
mapStateCalls++; | ||
return {}; // no change! | ||
}) | ||
class Container extends Component { | ||
render() { | ||
renderCalls++; | ||
return <Passthrough {...this.props} />; | ||
} | ||
} | ||
TestUtils.renderIntoDocument( | ||
<ProviderMock store={store}> | ||
<Container /> | ||
</ProviderMock> | ||
); | ||
expect(renderCalls).toBe(1); | ||
expect(mapStateCalls).toBe(2); | ||
store.dispatch({ type: 'APPEND', body: 'a'}); | ||
// After store a change mapState has been called | ||
expect(mapStateCalls).toBe(3); | ||
// But render is not because it did not make any actual changes | ||
expect(renderCalls).toBe(1); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
123294
33
2308
2
36