Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Mar 30, 2022. It is now read-only.

Commit cc5d916

Browse files
committed
fix configure store and reducer
1 parent 7c63ad5 commit cc5d916

File tree

3 files changed

+289
-29
lines changed

3 files changed

+289
-29
lines changed

‎src/features/text/TextDiv.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const callbackOnMount: CallbackOnStore = async (store) =>
6767
store.injectReducers(reducerCombo2);
6868

6969
const callbackOnUnmount: CallbackOnStore = async (store) =>
70-
store.removeReducers(['count']);
70+
store.removeReducers(['text']);
7171

7272
const TextDivWrap = () => (
7373
<DynamicStoreWrap

‎src/utils/redux/configureStore.test.ts

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
import { AnyAction } from '@reduxjs/toolkit';
2+
import configureStore from './configureStore';
3+
4+
describe('configureStore', () => {
5+
const inheritedProperties = ['getState', 'dispatch', 'subscribe'];
6+
const extendedProperties = [
7+
'reducer',
8+
'addReducer',
9+
'removeReducers',
10+
'injectReducers',
11+
'substituteReducers',
12+
];
13+
const expectedProperties = [...inheritedProperties, ...extendedProperties];
14+
15+
const testReducer1 = (state = '', action: AnyAction) => {
16+
switch (action.type) {
17+
case 'updateState1': {
18+
return action.payload;
19+
}
20+
default: {
21+
return state;
22+
}
23+
}
24+
};
25+
const testReducer2 = (
26+
state: { counter: number } = { counter: 0 },
27+
action: AnyAction
28+
) => {
29+
switch (action.type) {
30+
case 'incrementState2': {
31+
return { counter: state.counter + action.payload };
32+
}
33+
default: {
34+
return state;
35+
}
36+
}
37+
};
38+
39+
test('should create a store without error', () => {
40+
const store = configureStore({ reducer: {} });
41+
42+
expectedProperties.forEach((property) => {
43+
expect(store).toHaveProperty(property);
44+
});
45+
expect(store.reducer).toEqual({});
46+
expect(store.getState()).toEqual({});
47+
});
48+
49+
test('should accept reducer map objects without error', () => {
50+
const store = configureStore({
51+
reducer: {
52+
testReducer1,
53+
testReducer2,
54+
},
55+
});
56+
expectedProperties.forEach((property) => {
57+
expect(store).toHaveProperty(property);
58+
});
59+
expect(store.reducer).toEqual({
60+
testReducer1,
61+
testReducer2,
62+
});
63+
expect(store.getState()).toEqual({
64+
testReducer1: '',
65+
testReducer2: { counter: 0 },
66+
});
67+
68+
store.dispatch({ type: 'updateState1', payload: 'testing' });
69+
expect(store.getState()).toEqual({
70+
testReducer1: 'testing',
71+
testReducer2: { counter: 0 },
72+
});
73+
store.dispatch({ type: 'incrementState2', payload: 3 });
74+
expect(store.getState()).toEqual({
75+
testReducer1: 'testing',
76+
testReducer2: { counter: 3 },
77+
});
78+
});
79+
80+
describe('store.addReducer', () => {
81+
test('should be able to add a reducer', () => {
82+
const store = configureStore({
83+
reducer: { testReducer1 },
84+
});
85+
store.dispatch({ type: 'updateState1', payload: 'testing' });
86+
expect(store.getState()).toEqual({
87+
testReducer1: 'testing',
88+
});
89+
store.addReducer('testReducer2', testReducer2);
90+
expect(store.reducer).toEqual({ testReducer1, testReducer2 });
91+
92+
expect(store.getState()).toEqual({
93+
testReducer1: 'testing',
94+
testReducer2: { counter: 0 },
95+
});
96+
97+
store.dispatch({ type: 'incrementState2', payload: 3 });
98+
expect(store.getState()).toEqual({
99+
testReducer1: 'testing',
100+
testReducer2: { counter: 3 },
101+
});
102+
103+
store.dispatch({ type: 'updateState1', payload: 'testing2' });
104+
expect(store.getState()).toEqual({
105+
testReducer1: 'testing2',
106+
testReducer2: { counter: 3 },
107+
});
108+
});
109+
});
110+
111+
describe('store.removeReducers', () => {
112+
test('should be able to remove an existing reducer', () => {
113+
const store = configureStore({
114+
reducer: {
115+
testReducer1,
116+
testReducer2,
117+
},
118+
});
119+
expect(store.reducer).toEqual({ testReducer1, testReducer2 });
120+
expect(store.getState()).toEqual({
121+
testReducer1: '',
122+
testReducer2: { counter: 0 },
123+
});
124+
125+
store.removeReducers(['testReducer1']);
126+
expect(store.reducer).toEqual({ testReducer2 });
127+
128+
expect(store.getState()).toEqual({
129+
testReducer2: { counter: 0 },
130+
});
131+
132+
expect(store.dispatch({ type: 'updateState1', payload: 'testing' }));
133+
expect(store.getState()).toEqual({
134+
testReducer2: { counter: 0 },
135+
});
136+
137+
expect(store.dispatch({ type: 'incrementState2', payload: 2 }));
138+
expect(store.getState()).toEqual({
139+
testReducer2: { counter: 2 },
140+
});
141+
});
142+
143+
test('should maintian the same reducers if remove a non-existing reducer', () => {
144+
const store = configureStore({
145+
reducer: {
146+
testReducer1,
147+
testReducer2,
148+
},
149+
});
150+
expect(store.reducer).toEqual({ testReducer1, testReducer2 });
151+
expect(store.getState()).toEqual({
152+
testReducer1: '',
153+
testReducer2: { counter: 0 },
154+
});
155+
156+
store.removeReducers(['testReducer3']);
157+
expect(store.reducer).toEqual({ testReducer1, testReducer2 });
158+
159+
expect(store.getState()).toEqual({
160+
testReducer1: '',
161+
testReducer2: { counter: 0 },
162+
});
163+
164+
expect(store.dispatch({ type: 'updateState1', payload: 'testing' }));
165+
expect(store.getState()).toEqual({
166+
testReducer1: 'testing',
167+
testReducer2: { counter: 0 },
168+
});
169+
170+
expect(store.dispatch({ type: 'incrementState2', payload: 2 }));
171+
expect(store.getState()).toEqual({
172+
testReducer1: 'testing',
173+
testReducer2: { counter: 2 },
174+
});
175+
});
176+
});
177+
178+
describe('store.injectReducers', () => {
179+
test('should be able to inject reducers', () => {
180+
const store = configureStore({ reducer: {} });
181+
expect(store.reducer).toEqual({});
182+
expect(store.dispatch({ type: 'updateState1', payload: 'testing' }));
183+
expect(store.getState()).toEqual({});
184+
185+
store.injectReducers({ testReducer1, testReducer2 });
186+
expect(store.reducer).toEqual({ testReducer1, testReducer2 });
187+
expect(store.getState()).toEqual({
188+
testReducer1: '',
189+
testReducer2: { counter: 0 },
190+
});
191+
192+
expect(store.dispatch({ type: 'updateState1', payload: 'testing' }));
193+
expect(store.getState()).toEqual({
194+
testReducer1: 'testing',
195+
testReducer2: { counter: 0 },
196+
});
197+
198+
expect(store.dispatch({ type: 'incrementState2', payload: 2 }));
199+
expect(store.getState()).toEqual({
200+
testReducer1: 'testing',
201+
testReducer2: { counter: 2 },
202+
});
203+
});
204+
});
205+
206+
describe('store.substituteReducers', () => {
207+
test('should be able to substitute a reducer', () => {
208+
const store = configureStore({ reducer: { testReducer1 } });
209+
expect(store.reducer).toEqual({ testReducer1 });
210+
expect(store.getState()).toEqual({
211+
testReducer1: '',
212+
});
213+
214+
store.substituteReducers({ testReducer2 });
215+
expect(store.reducer).toEqual({ testReducer2 });
216+
expect(store.getState()).toEqual({
217+
testReducer2: {
218+
counter: 0,
219+
},
220+
});
221+
222+
expect(store.dispatch({ type: 'updateState1', payload: 'testing' }));
223+
expect(store.getState()).toEqual({
224+
testReducer2: { counter: 0 },
225+
});
226+
227+
expect(store.dispatch({ type: 'incrementState2', payload: 2 }));
228+
expect(store.getState()).toEqual({
229+
testReducer2: { counter: 2 },
230+
});
231+
});
232+
233+
test('should keep the existing state if the subtituted reducers include existing reducers', () => {
234+
const store = configureStore({ reducer: { testReducer1 } });
235+
expect(store.reducer).toEqual({ testReducer1 });
236+
expect(store.getState()).toEqual({
237+
testReducer1: '',
238+
});
239+
240+
expect(store.dispatch({ type: 'updateState1', payload: 'testing' }));
241+
expect(store.getState()).toEqual({
242+
testReducer1: 'testing',
243+
});
244+
245+
store.substituteReducers({ testReducer1, testReducer2 });
246+
expect(store.reducer).toEqual({ testReducer1, testReducer2 });
247+
expect(store.getState()).toEqual({
248+
testReducer1: 'testing',
249+
testReducer2: {
250+
counter: 0,
251+
},
252+
});
253+
254+
expect(store.dispatch({ type: 'updateState1', payload: 'testing2' }));
255+
expect(store.getState()).toEqual({
256+
testReducer1: 'testing2',
257+
testReducer2: { counter: 0 },
258+
});
259+
260+
expect(store.dispatch({ type: 'incrementState2', payload: 2 }));
261+
expect(store.getState()).toEqual({
262+
testReducer1: 'testing2',
263+
testReducer2: { counter: 2 },
264+
});
265+
});
266+
});
267+
});

‎src/utils/redux/configureStore.ts

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ import {
1111
} from '@reduxjs/toolkit';
1212
import objectAssign from '../common/objectAssign';
1313

14-
interface StoreReducerEnhanced<S = any, A extends Action<any> = AnyAction> {
15-
commonReducer: ReducersMapObject<S, A>;
16-
asyncReducer: ReducersMapObject<any, AnyAction>;
14+
interface StoreReducerEnhanced {
15+
reducer: ReducersMapObject;
1716
addReducer: <S = any, A extends Action<any> = AnyAction>(
1817
key: string,
1918
addedReducer: Reducer<S, A>
@@ -22,15 +21,15 @@ interface StoreReducerEnhanced<S = any, A extends Action<any> = AnyAction> {
2221
injectReducers: <S = any, A extends Action<any> = AnyAction>(
2322
reducers: ReducersMapObject<S, A>
2423
) => void;
25-
substitueReducers: <S = any, A extends Action<any> = AnyAction>(
24+
substituteReducers: <S = any, A extends Action<any> = AnyAction>(
2625
reducers: ReducersMapObject<S, A>
2726
) => void;
2827
}
2928

3029
export interface ReducerEnhancedStore<
3130
S = any,
3231
A extends Action<any> = AnyAction
33-
> extends Store<S, A>, StoreReducerEnhanced<S,A> {}
32+
> extends Store<S, A>, StoreReducerEnhanced {}
3433

3534
export interface ModifiedConfigureStoreOptions<
3635
S = any,
@@ -46,13 +45,11 @@ const modifiedConfigureStore = <S = any, A extends Action<any> = AnyAction>({
4645
}: ModifiedConfigureStoreOptions<S, A>) => {
4746
let keysToRemove: string[] = [];
4847

49-
const commonReducer = reducer;
50-
5148
const createReducer = <
5249
S extends object = {},
5350
A extends Action<any> = AnyAction
5451
>(
55-
reducerObj?: ReducersMapObject<S, A>
52+
reducerObj: ReducersMapObject<S, A>
5653
): Reducer<S, A> => (state = {} as S, action) => {
5754
let updatedState = state;
5855
if (keysToRemove.length > 0) {
@@ -62,53 +59,49 @@ const modifiedConfigureStore = <S = any, A extends Action<any> = AnyAction>({
6259
);
6360
keysToRemove = [];
6461
}
65-
return combineReducers<S, A>({
66-
...commonReducer,
67-
...reducerObj,
68-
})(updatedState, action);
62+
return combineReducers<S, A>(reducerObj)(updatedState, action);
6963
};
7064

7165
const store: ReducerEnhancedStore<S, A> = Object.assign(
7266
configureStore({ reducer, ...restConfig }),
7367
{
74-
commonReducer,
75-
asyncReducer: {},
68+
reducer,
7669

7770
addReducer: (key, addedReducer) => {
78-
if (!key || store.asyncReducer[key]) {
71+
if (!key || store.reducer[key]) {
7972
return;
8073
}
81-
store.asyncReducer[key] = addedReducer as Reducer<any, AnyAction>;
82-
store.replaceReducer(combineReducers(store.asyncReducer));
74+
store.reducer[key] = addedReducer as Reducer<any, AnyAction>;
75+
store.replaceReducer(createReducer(store.reducer));
8376
},
8477

8578
removeReducers: (keys) => {
8679
keys.forEach((key) => {
87-
if (!key || !store.asyncReducer[key]) {
80+
if (!key || !store.reducer[key]) {
8881
return;
8982
}
9083
keysToRemove.push(key);
9184
});
92-
store.asyncReducer = objectAssign(([k]) => !keysToRemove.includes(k))(
85+
store.reducer = objectAssign(([k]) => !keysToRemove.includes(k))(
9386
{},
94-
store.asyncReducer
87+
store.reducer
9588
);
96-
store.replaceReducer(createReducer(store.asyncReducer));
89+
store.replaceReducer(createReducer(store.reducer));
9790
},
9891

9992
injectReducers: (reducers) => {
100-
objectAssign()(store.asyncReducer, reducers);
101-
store.replaceReducer(createReducer(store.asyncReducer));
93+
objectAssign()(store.reducer, reducers);
94+
store.replaceReducer(createReducer(store.reducer));
10295
},
10396

104-
substitueReducers: (reducers) => {
97+
substituteReducers: (reducers) => {
10598
keysToRemove.push(
106-
...Object.keys(store.asyncReducer).filter((k) => !(k in reducers))
99+
...Object.keys(store.reducer).filter((k) => !(k in reducers))
107100
);
108-
store.asyncReducer = objectAssign()({}, reducers);
109-
store.replaceReducer(createReducer(store.asyncReducer));
101+
store.reducer = objectAssign()({}, reducers);
102+
store.replaceReducer(createReducer(store.reducer));
110103
},
111-
} as StoreReducerEnhanced<S,A>
104+
} as StoreReducerEnhanced
112105
);
113106

114107
return store;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /