diff --git a/README.md b/README.md index fb2141e..7ecf7e1 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ In 'redux-saga', to change the local state when an action is dispatched, it is necessary to change local state to globally using Redux, Context and etc. It becomes maintenance difficult if these kinds of works are repeated. -To solve this problem I made 'redux-action-listener' by inheriting the work of [redux-listener](https://github.com/Gaya/redux-listeners). +To solve this problem I made 'redux-action-listener' by inheriting the work of [redux-listener](https://github.com/Gaya/redux-listeners). You can make side effects and listening actions more simply and lightly than 'redux-saga'. Also, by providing a hook version, you don't have to move local state to global state. diff --git a/package-lock.json b/package-lock.json index 8b46a02..3f3b3be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-action-listener", - "version": "1.2.7", + "version": "1.2.8-alpha.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 92512a9..3bcb69e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-action-listener", - "version": "1.2.7", + "version": "1.2.8-alpha.0", "description": "Middleware which allows listening actions of Context and Redux", "main": "lib", "files": [ @@ -23,8 +23,7 @@ "test:c": "jest --coverage", "lint": "eslint --ext js,ts,jsx,tsx src test", "lint:p": "prettier --write \"{src,test}/**/*.{js,ts,jsx,tsx}\" \"**/*.md\"", - "prepublishOnly": "yarn test && yarn lint && yarn lint:p", - "prepare": "yarn build" + "prepublishOnly": "yarn test && yarn lint && yarn lint:p && yarn build" }, "lint-staged": { "src/**/*.{js,jsx,ts,tsx}": [ diff --git a/src/react/useActionListener.tsx b/src/react/useActionListener.tsx index 22f8db0..ffba26a 100644 --- a/src/react/useActionListener.tsx +++ b/src/react/useActionListener.tsx @@ -29,7 +29,7 @@ const useActionListener: UseActionListener = (actionName, cb) => { return () => { actionHandler?.removeListener(hash); }; - }, [actionName]); + }, [JSON.stringify(actionName)]); }; export default useActionListener; diff --git a/test/react/useActionListener.test.tsx b/test/react/useActionListener.test.tsx index 889f240..cab091f 100644 --- a/test/react/useActionListener.test.tsx +++ b/test/react/useActionListener.test.tsx @@ -55,19 +55,86 @@ test('Should apply latest callback', () => { expect(listenMiddleware.listeners.size).toBe(1); }); -test('Should remove first listener when component unmounted', () => { +test('Should remove first listener when action name is chagned and register new one', () => { const listenMiddleware = createMiddleware(); + // it listens TEST actions const mockAction = 'TEST'; + let cntForTest = 0; + let cntForOthers = 0; const { rerender } = renderHook( - ({ action }) => useActionListener(action, () => {}), + ({ action }) => + useActionListener(action, () => { + if (action === 'TEST') { + cntForTest += 1; + } else { + cntForOthers += 1; + } + }), { initialProps: { action: mockAction } } ); const middleware = listenMiddleware(mockStore)(mockNext); middleware({ type: 'TEST' }); expect(listenMiddleware.listeners.size).toBe(1); - rerender({ action: 'OCCURS_UNMOUNT' }); + expect(cntForTest).toBe(1); + + // now action name is chagned + // it will remove listeneing listener that listens TEST + // and will create new listener for CHANGE_ACTION + rerender({ action: 'CHANGE_ACTION' }); expect(listenMiddleware.listeners.size).toBe(1); + expect(cntForTest).toBe(1); + expect(cntForOthers).toBe(0); + + // dispatch TEST + middleware({ type: 'TEST' }); + // should be 1 because the action TEST is removed + expect(cntForTest).toBe(1); + + middleware({ type: 'CHANGE_ACTION' }); + // should be 1 because the CHANGE_ACTION is registed + expect(cntForTest).toBe(1); +}); + +test('Should remove first listener when action list is chagned and register new one', () => { + const listenMiddleware = createMiddleware(); + // it listens [TEST] actions + const mockAction = ['TEST']; + let cntForTest = 0; + let cntForOthers = 0; + const { rerender } = renderHook( + ({ action }) => + useActionListener(action, () => { + if (action[0] === 'TEST') { + cntForTest += 1; + } else { + cntForOthers += 1; + } + }), + { initialProps: { action: mockAction } } + ); + + const middleware = listenMiddleware(mockStore)(mockNext); + middleware({ type: 'TEST' }); + expect(listenMiddleware.listeners.size).toBe(1); + expect(cntForTest).toBe(1); + + // now action name is chagned + // it will remove listeneing listener that listens TEST + // and will create new listener for CHANGE_ACTION + rerender({ action: ['CHANGE_ACTION'] }); + expect(listenMiddleware.listeners.size).toBe(1); + expect(cntForTest).toBe(1); + expect(cntForOthers).toBe(0); + + // dispatch TEST + middleware({ type: 'TEST' }); + // should be 1 because the action TEST is removed + expect(cntForTest).toBe(1); + + middleware({ type: 'CHANGE_ACTION' }); + // should be 1 because the CHANGE_ACTION is registed + expect(cntForTest).toBe(1); }); test('Should register multiple listeners with same action name', () => {