Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 13 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Subscribe and UnSubscribe action for Redux
## Usage

For Middleware

```js
import {createStore} from 'redux';
import Subscriber from 'redux-subscriber-middleware';
Expand All @@ -28,6 +29,7 @@ let store = createStore(
```

Inside the script

```js
// or you can just import "subscribe" function from the package
import { subscribeAction, subscribeOnceAction, unsubscribeAction } from 'redux-subscriber-middleware';
Expand All @@ -38,8 +40,17 @@ dispatch(subscribeAction('ACTION_YOU_WANT_TO_SUBSCRIBE', CALLBACK_FUNCTION));
// for one time
dispatch(subscribeOnceAction('ACTION_YOU_WANT_TO_SUBSCRIBE', CALLBACK_FUNCTION));

// for unsubscribe
dispatch(unsubscribeAction('ACTION_YOU_WANT_TO_SUBSCRIBE'));
// unsubscribe all callbacks for action
dispatch(unsubscribeAction('ACTION_YOU_WANT_TO_UNSUBSCRIBE'));

// unsubscribe specific callback for action
dispatch(unsubscribeAction('ACTION_YOU_WANT_TO_UNSUBSCRIBE', CALLBACK_FUNCTION));

// unsubscribe specific callback for all actions
dispatch(unsubscribeAction(null, CALLBACK_FUNCTION));

// unsubscribe everything
dispatch(unsubscribeAction());

```

60 changes: 57 additions & 3 deletions __tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import Subscriber, { subscribeAction, subscribeOnceAction, unsubscribeAction } f

let store;
let mockCallback;
const addAction = () => ({ type: 'ADD_ACTION' });
const addAction = () => ({ type: 'ADD_ACTION' });
const otherAction = () => ({ type: 'OTHER_ACTION' });

function initialize() {
const middlewares = [Subscriber()];
Expand Down Expand Up @@ -77,12 +78,12 @@ describe('redux-subscriber-middleware', () => {
beforeEach(() => {
initialize();
});
it('should call the callback function one time', () => {
it('should call the callback function two times', () => {
store.dispatch(addAction());
store.dispatch(subscribeAction('ADD_ACTION', mockCallback));
store.dispatch(addAction());
store.dispatch(addAction());
expect(mockCallback.mock.calls.length).toEqual(3);
expect(mockCallback.mock.calls.length).toEqual(2);
});
});
});
Expand All @@ -95,5 +96,58 @@ describe('redux-subscriber-middleware', () => {
store.dispatch(addAction());
expect(mockCallback.mock.calls.length).toEqual(1);
});

it('should unsubscribe the specific callback given', () => {
let otherCallback = jest.fn();
let onceCallback = jest.fn();

store.dispatch(subscribeAction('ADD_ACTION', mockCallback));
store.dispatch(subscribeAction('ADD_ACTION', otherCallback));
store.dispatch(addAction());

store.dispatch(subscribeOnceAction('ADD_ACTION', onceCallback));
expect(onceCallback).not.toBeCalled();
store.dispatch(unsubscribeAction('ADD_ACTION', otherCallback));
store.dispatch(unsubscribeAction('ADD_ACTION', onceCallback));

store.dispatch(addAction());

expect(otherCallback.mock.calls.length).toEqual(1);
expect(mockCallback.mock.calls.length).toEqual(2);
});

it('should unsubscribe the specific callback given for all actions', () => {
let onceCallback = jest.fn();

store.dispatch(subscribeAction('ADD_ACTION', mockCallback));
store.dispatch(subscribeAction('OTHER_ACTION', mockCallback));
store.dispatch(addAction());
store.dispatch(otherAction());

store.dispatch(subscribeOnceAction('ADD_ACTION', onceCallback));
expect(onceCallback).not.toBeCalled();
store.dispatch(unsubscribeAction(null, mockCallback));
store.dispatch(unsubscribeAction(null, onceCallback));

store.dispatch(addAction());
store.dispatch(otherAction());

expect(mockCallback.mock.calls.length).toEqual(2);
});

it('should unsubscribe ALL THE THINGS', () => {
let otherCallback = jest.fn();

store.dispatch(subscribeAction('ADD_ACTION', mockCallback));
store.dispatch(subscribeAction('OTHER_ACTION', mockCallback));
store.dispatch(subscribeAction('OTHER_ACTION', otherCallback));
store.dispatch(addAction());
store.dispatch(otherAction());
store.dispatch(unsubscribeAction());
store.dispatch(addAction());
store.dispatch(otherAction());
expect(mockCallback.mock.calls.length).toEqual(2);
expect(otherCallback.mock.calls.length).toEqual(1);
});
});
});
89 changes: 52 additions & 37 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,62 @@
'use strict';


export const SUBSCRIBE = 'REDUX_ACTION_SUBSCRIBE';
export const SUBSCRIBEONCE = 'REDUX_ACTION_SUBSCRIBEONCE';
export const UNSUBSCRIBE = 'REDUX_ACTION_UNSUBSCRIBE';

export default () => {
const actionList = [];
const subscribe = {};
const subscribeOnce = {};
function subscribeHandler(subscribe, event, cb, isMultiple = false) {
const _subscribe = subscribe;
if (actionList.indexOf(event) >= 0) {
cb();
isMultiple ? _subscribe[event] = [cb] : '';
} else if (_subscribe[event]) {
_subscribe[event].push(cb);
function subscribeHandler(repo, event, cb) {
if (repo[event]) {
repo[event].push(cb);
} else {
_subscribe[event] = [cb];
repo[event] = [cb]; // eslint-disable-line no-param-reassign
}
}

return store => next => (action) => {
return store => next => (action) => { // eslint-disable-line no-unused-vars
const result = next(action);
if (action.type === SUBSCRIBE || action.type === SUBSCRIBEONCE || action.type === UNSUBSCRIBE) {
switch (action.type) {
case SUBSCRIBE:
subscribeHandler(subscribe, action.payload.event, action.payload.callback ,true);
break;
case SUBSCRIBEONCE:
subscribeHandler(subscribeOnce, action.payload.event, action.payload.callback);
break;
case UNSUBSCRIBE:
if (subscribe[action.payload.event]) {
delete subscribe[action.payload.event];
}
if (subscribeOnce[action.payload.event]) {
delete subscribeOnce[action.payload.event];
}
break;
default:
case SUBSCRIBE:
subscribeHandler(subscribe, action.payload.event, action.payload.callback, true);
break;
case SUBSCRIBEONCE:
subscribeHandler(subscribeOnce, action.payload.event, action.payload.callback);
break;
case UNSUBSCRIBE: // eslint-disable-line no-case-declarations
const { event, callback } = action.payload;
if (event) {
if (callback) {
if (subscribe[event]) {
subscribe[event] = subscribe[event].filter(cb => cb !== callback);
}

if (subscribeOnce[event]) {
subscribeOnce[event] = subscribeOnce[event].filter(cb => cb !== callback);
}
} else {
delete subscribe[event];
delete subscribeOnce[event];
}
} else if (callback) {
// eslint-disable-next-line no-return-assign
Object.keys(subscribe).forEach(k =>
subscribe[k] = subscribe[k].filter(cb => cb !== callback),
);
// eslint-disable-next-line no-return-assign
Object.keys(subscribeOnce).forEach(k =>
subscribeOnce[k] = subscribeOnce[k].filter(cb => cb !== callback),
);
} else {
Object.keys(subscribe).forEach(k => delete subscribe[k]);
Object.keys(subscribeOnce).forEach(k => delete subscribeOnce[k]);
}
break;
default:
}
} else {
actionList.push(action.type);
if (subscribe[action.type]) {
subscribe[action.type].forEach(cb => cb(result));
}
Expand All @@ -58,21 +73,21 @@ export const subscribeAction = (event, callback) => ({
type: SUBSCRIBE,
payload: {
event,
callback
}
callback,
},
});

export const subscribeOnceAction = (event, callback) => ({
type: SUBSCRIBEONCE,
payload: {
event,
callback
}
callback,
},
});

export const unsubscribeAction = event => ({
type: UNSUBSCRIBE,
payload: {
event
}
});
export const unsubscribeAction = (event, callback = null) => {
const action = { type: UNSUBSCRIBE, payload: { } };
if (event) action.payload.event = event;
if (callback) action.payload.callback = callback;
return action;
};