diff --git a/src/components/connectAdvanced.js b/src/components/connectAdvanced.js index 3fff8ee26..a68b5f060 100644 --- a/src/components/connectAdvanced.js +++ b/src/components/connectAdvanced.js @@ -68,6 +68,9 @@ export default function connectAdvanced( // the key of props/context to get the store storeKey = 'store', + // the key of context to get the subscription + subKey, + // if true, the wrapped element is exposed by this HOC via the getWrappedInstance() function. withRef = false, @@ -75,7 +78,7 @@ export default function connectAdvanced( ...connectOptions } = {} ) { - const subscriptionKey = storeKey + 'Subscription' + const subscriptionKey = subKey || `${storeKey}Subscription` const version = hotReloadingVersion++ const contextTypes = { diff --git a/src/connect/selectorFactory.js b/src/connect/selectorFactory.js index 4479431e0..de34b3361 100644 --- a/src/connect/selectorFactory.js +++ b/src/connect/selectorFactory.js @@ -1,5 +1,5 @@ import verifySubselectors from './verifySubselectors' - + export function impureFinalPropsSelectorFactory( mapStateToProps, mapDispatchToProps, @@ -64,7 +64,7 @@ export function pureFinalPropsSelectorFactory( const nextStateProps = mapStateToProps(state, ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps - + if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) diff --git a/test/components/Provider.spec.js b/test/components/Provider.spec.js index 449cdf0fb..cff63e96f 100644 --- a/test/components/Provider.spec.js +++ b/test/components/Provider.spec.js @@ -8,7 +8,7 @@ import { Provider, createProvider, connect } from '../../src/index' describe('React', () => { describe('Provider', () => { - const createChild = (storeKey = 'store') => { + const createChild = (storeKey = 'store', subKey = 'subKey') => { class Child extends Component { render() { return
@@ -16,7 +16,8 @@ describe('React', () => { } Child.contextTypes = { - [storeKey]: PropTypes.object.isRequired + [storeKey]: PropTypes.object.isRequired, + [subKey]: PropTypes.object, } return Child @@ -73,21 +74,39 @@ describe('React', () => { }) it('should add the store to the child context using a custom store key', () => { - const store = createStore(() => ({})) - const CustomProvider = createProvider('customStoreKey'); - const CustomChild = createChild('customStoreKey'); - - const spy = jest.spyOn(console, 'error').mockImplementation(() => {}); - const testRenderer = TestRenderer.create( - - - - ) - spy.mockRestore() - expect(spy).toHaveBeenCalledTimes(0) + const store = createStore(() => ({})) + const CustomProvider = createProvider('customStoreKey'); + const CustomChild = createChild('customStoreKey'); + + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const testRenderer = TestRenderer.create( + + + + ) + spy.mockRestore() + expect(spy).toHaveBeenCalledTimes(0) + + const child = testRenderer.root.findByType(CustomChild).instance + expect(child.context.customStoreKey).toBe(store) + }) + + it('should add the subscription to the child context using a custom subscription key', () => { + const store = createStore(() => ({})) + const CustomProvider = createProvider('customStoreKey', 'customSubKey') + const CustomChild = createChild('customStoreKey', 'customSubKey') + + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + const testRenderer = TestRenderer.create( + + + + ) + spy.mockRestore() + expect(spy).toHaveBeenCalledTimes(0) - const child = testRenderer.root.findByType(CustomChild).instance - expect(child.context.customStoreKey).toBe(store) + const child = testRenderer.root.findByType(CustomChild).instance + expect(child.context.customSubKey).toBe(null) }) it('should warn once when receiving a new store in props', () => { diff --git a/test/components/connect.spec.js b/test/components/connect.spec.js index 2d3e975ce..a6cca05c0 100644 --- a/test/components/connect.spec.js +++ b/test/components/connect.spec.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types' import ReactDOM from 'react-dom' import TestRenderer from 'react-test-renderer' import { createStore } from 'redux' -import { connect } from '../../src/index' +import { connect, createProvider } from '../../src/index' describe('React', () => { describe('connect', () => { @@ -2324,5 +2324,62 @@ describe('React', () => { expect(mapStateToPropsC).toHaveBeenCalledTimes(2) expect(mapStateToPropsD).toHaveBeenCalledTimes(2) }) + + it('should receive the store in the context using a custom store key', () => { + const store = createStore(() => ({})) + const CustomProvider = createProvider('customStoreKey') + const connectOptions = { storeKey: 'customStoreKey' } + + @connect(undefined, undefined, undefined, connectOptions) + class Container extends Component { + render() { + return + } + } + + const testRenderer = TestRenderer.create( + + + + ) + + const container = testRenderer.root.findByType(Container) + expect(container.instance.store).toBe(store) + }) + + it('should receive the subscription in the context using a custom store key', () => { + const store = createStore(() => ({})) + const CustomProvider = createProvider('customStoreKey', 'customSubKey') + const connectOptions = { storeKey: 'customStoreKey', subKey: 'customSubKey' } + + @connect(() => ({}), undefined, undefined, connectOptions) + class OuterContainer extends Component { + render() { + return Children.only(this.props.children) + } + } + + @connect(() => ({}), undefined, undefined, connectOptions) + class NestedContainer extends Component { + render() { + return + } + } + + const testRenderer = TestRenderer.create( + + + + + + ) + + const outerContainer = testRenderer.root.findByType(OuterContainer) + const nestedContainer = testRenderer.root.findByType(NestedContainer) + expect(outerContainer.instance.context.customSubKey).toBe(null) + expect(nestedContainer.instance.context.customSubKey).toBe( + outerContainer.instance.subscription + ) + }) }) })