diff --git a/README.md b/README.md index 0fa117d..50c3fdb 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,9 @@ Here our state looks something like `{ status: 'foobar' }` methods: { doMagic: function () { this.createAction() + }, + doMagic2: function () { + this.$emit('customevent') } } } @@ -103,6 +106,10 @@ Here our state looks something like `{ status: 'foobar' }` const mapDispatch = { createAction } + const mapEventDispatch = { + customevent: createAction + } + export default connect(mapState, mapDispatch)(component) ``` diff --git a/dist/revux.js b/dist/revux.js index de93738..df9a384 100644 --- a/dist/revux.js +++ b/dist/revux.js @@ -68,18 +68,19 @@ function shallowEqual(objA, objB) { return true; } -var wrapActionCreators = function wrapActionCreators(actionCreators) { - return function (dispatch) { - return redux.bindActionCreators(actionCreators, dispatch); - }; -}; - var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var defaultMapState = function defaultMapState() { return {}; }; var defaultMapDispatch = {}; +var defaultEventDispatch = {}; + +var forEach = function forEach(obj, iterator) { + return Object.keys(obj).forEach(function (key) { + return iterator(key, obj[key]); + }); +}; var normalizeMapState = function normalizeMapState(mapState) { if (typeof mapState === 'function') { @@ -103,6 +104,7 @@ var connector = function connector() { var _mapState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultMapState; var mapDispatch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultMapDispatch; + var eventDispatch = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultEventDispatch; return function (component) { var mapState = normalizeMapState(_mapState); return { @@ -112,7 +114,7 @@ var connector = function connector() { data: function data() { var initData = {}; - var mapData = _extends({}, mapState(this.$$store.getState()), wrapActionCreators(mapDispatch)(this.$$store.dispatch)); + var mapData = _extends({}, mapState(this.$$store.getState()), redux.bindActionCreators(mapDispatch, this.$$store.dispatch)); Object.keys(mapData).forEach(function (key) { initData[key] = mapData[key]; @@ -124,6 +126,11 @@ var connector = function connector() { var _this = this; var vm = this; + + forEach(redux.bindActionCreators(eventDispatch, this.$$store.dispatch), function (eventName, dispatcher) { + return vm.$on(eventName, dispatcher); + }); + var getMappedState = function getMappedState(state) { return mapState(state); }; diff --git a/src/connector.js b/src/connector.js index 8923f48..2e8688f 100644 --- a/src/connector.js +++ b/src/connector.js @@ -1,10 +1,14 @@ +import { bindActionCreators } from 'redux' + import { shallowEqual, - wrapActionCreators } from './utils/index' const defaultMapState = () => ({}) const defaultMapDispatch = {} +const defaultEventDispatch = {} + +const forEach = (obj, iterator) => Object.keys(obj).forEach(key => iterator(key, obj[key])) const normalizeMapState = mapState => { if (typeof mapState === 'function') { @@ -24,7 +28,7 @@ const normalizeMapState = mapState => { } } -const connector = (_mapState = defaultMapState, mapDispatch = defaultMapDispatch) => component => { +const connector = (_mapState = defaultMapState, mapDispatch = defaultMapDispatch, eventDispatch = defaultEventDispatch) => component => { const mapState = normalizeMapState(_mapState); return { name: `connect-${component.name}`, @@ -35,7 +39,7 @@ const connector = (_mapState = defaultMapState, mapDispatch = defaultMapDispatch const initData = {} const mapData = { ...mapState(this.$$store.getState()), - ...wrapActionCreators(mapDispatch)(this.$$store.dispatch) + ...bindActionCreators(mapDispatch, this.$$store.dispatch) } Object.keys(mapData).forEach(key => { @@ -47,6 +51,12 @@ const connector = (_mapState = defaultMapState, mapDispatch = defaultMapDispatch created () { const vm = this + + forEach( + bindActionCreators(eventDispatch, this.$$store.dispatch), + (eventName, dispatcher) => vm.$on(eventName, dispatcher) + ) + const getMappedState = state => mapState(state) const observeStore = (store, select, onChange) => { diff --git a/src/utils/index.js b/src/utils/index.js index 0218e35..29549a6 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,7 +1,5 @@ import shallowEqual from './shallowEqual' -import wrapActionCreators from './wrapActionCreators' export { - shallowEqual, - wrapActionCreators + shallowEqual } diff --git a/src/utils/wrapActionCreators.js b/src/utils/wrapActionCreators.js deleted file mode 100644 index 1dfea7e..0000000 --- a/src/utils/wrapActionCreators.js +++ /dev/null @@ -1,7 +0,0 @@ -import { - bindActionCreators -} from 'redux' - -const wrapActionCreators = (actionCreators) => dispatch => bindActionCreators(actionCreators, dispatch) - -export default wrapActionCreators diff --git a/test/connector.spec.js b/test/connector.spec.js index d6bf273..2948f64 100644 --- a/test/connector.spec.js +++ b/test/connector.spec.js @@ -181,6 +181,55 @@ describe('Connector', () => { }) + describe('events mapping', () => { + let dispatchStub + const originalDispatch = store.dispatch + beforeEach(() => { + dispatchStub = sinon.stub().returns() + store.dispatch = dispatchStub + }) + + afterEach(() => { + store.dispatch = originalDispatch + }) + + it('should map actions on events on connected component', () => { + let vm + let actionCreator = sinon.stub().returns({type: 'DO_THIS'}); + + const baseComponent = { + created () { + vm = this + }, + render () {} + } + + const mapEvents = { + eventName: actionCreator + } + + new Vue({ + template: ``, + provide: { + $$store: store + }, + components: { + connected: { + template: ``, + components: { + connectedComponent: connector(undefined, undefined, mapEvents)(baseComponent) + } + } + } + }).$mount() + + vm.$emit('eventName'); + + expect(actionCreator.called, 'action creator was not called').to.be.true + expect(store.dispatch.called, 'dispatch was not called').to.be.true + }) + }) + it('should override and use mapDispatch value if the same key is defined both in mapState and mapDispatch', () => { let vm const baseComponent = {