Skip to content
This repository was archived by the owner on Feb 3, 2020. It is now read-only.

Commit ee82164

Browse files
authored
Merge pull request #7 from cinnabarcaracal/patch-2
Allow returning arbitrary data from the handleAction function
2 parents 3ce8234 + e0bd7c7 commit ee82164

File tree

4 files changed

+51
-2
lines changed

4 files changed

+51
-2
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { createAction, handleAction, reduceReducers } from 'redux-ts-utils';
2424
const increment = createAction<void>('increment');
2525
const decrement = createAction<void>('decrement');
2626
const add = createAction<number>('add');
27+
const override = createAction<number>('override');
2728

2829
// Reducer
2930

@@ -45,6 +46,9 @@ const reducer = reduceReducers<State>([
4546
handleAction(add, (state, { payload }) => {
4647
state.counter += payload;
4748
}),
49+
handleAction(override, (_, { payload }) => ({
50+
counter: payload,
51+
})),
4852
], initialState);
4953

5054
// Store
@@ -142,6 +146,9 @@ object. [`immer`] will also provide you with a mapped type (`Draft`) of your
142146
state with all `readonly` modifiers removed (it will also remove `Readonly`
143147
mapped types and convert `ReadonlyArray`s to standard arrays).
144148

149+
If your mutation function returns a value other than `undefined`, and does not mutate the
150+
incoming state object, that return value will become the new state instead.
151+
145152
### `reduceReducers<S>(reducers: Reducer[], initialState?: S)`
146153

147154
The `reduceReducers` function takes an array of reducer functions and an

src/example.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { createAction, handleAction, reduceReducers } from '.';
88
const increment = createAction<void>('increment');
99
const decrement = createAction<void>('decrement');
1010
const add = createAction<number>('add');
11+
const override = createAction<number>('override');
1112

1213
// Reducer
1314

@@ -29,6 +30,9 @@ const reducer = reduceReducers<State>([
2930
handleAction(add, (state, { payload }) => {
3031
state.counter += payload;
3132
}),
33+
handleAction(override, (_, { payload }) => ({
34+
counter: payload,
35+
})),
3236
], initialState);
3337

3438
// Store

src/handle-action.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,35 @@ test('handles specific action with payload', () => {
3232
expect(newState2).toEqual({ counter: 0 });
3333
expect(newState2).toBe(state);
3434
});
35+
36+
test('handles specific action with payload by returning value directly', () => {
37+
const ac1 = createAction<{ num: number }>('foo3');
38+
const state: { readonly counter: number } = { counter: 0 };
39+
const re = handleAction<typeof state>(ac1, (draft, { payload }) => ({
40+
counter: draft.counter + payload.num,
41+
}), state);
42+
const newState1 = re(state, ac1({ num: 7 }));
43+
expect(newState1).toEqual({ counter: 7 });
44+
expect(newState1).not.toBe(state);
45+
});
46+
47+
test('handles specific action with payload and ignores directly returned value if draft is mutated', () => {
48+
const ac1 = createAction<{ num: number }>('foo4');
49+
const state: { readonly counter: number } = { counter: 0 };
50+
const re = handleAction<typeof state>(ac1, (draft, { payload }) => {
51+
draft.counter += payload.num;
52+
return 'unintended return value';
53+
}, state);
54+
const newState1 = re(state, ac1({ num: 10 }));
55+
expect(newState1).toEqual({ counter: 10 });
56+
expect(newState1).not.toBe(state);
57+
});
58+
59+
test('handles specific action and uses previous state if directly return value is undefined', () => {
60+
const ac1 = createAction<void>('foo5');
61+
const state: { readonly baz: number } = { baz: 0 };
62+
const re = handleAction<typeof state>(ac1, () => undefined, state);
63+
const newState1 = re(state, ac1());
64+
expect(newState1).toEqual({ baz: 0 });
65+
expect(newState1).toBe(state);
66+
});

src/handle-action.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,14 @@ export default function handleAction<S, AC extends TsActionCreator<any> = any>(
2323
return (state: S | undefined, action: ReturnType<AC>) => {
2424
if (action.type === ac.type && state) {
2525
const draft = createDraft(state);
26-
re(draft, action);
27-
return finishDraft(draft);
26+
const reResult = re(draft, action);
27+
const finishedDraft = finishDraft(draft);
28+
29+
if (finishedDraft === state && reResult !== undefined) {
30+
return reResult;
31+
}
32+
33+
return finishedDraft;
2834
}
2935
return (state || s) as any;
3036
};

0 commit comments

Comments
 (0)