Skip to content

Commit 7b4b717

Browse files
authored
Introducing retained flag in modules so they are retained even when the component is unmounted (#89)
* Introduce retained functionality for modules
1 parent a46e87b commit 7b4b717

File tree

5 files changed

+53
-11
lines changed

5 files changed

+53
-11
lines changed

packages/redux-dynamic-modules-core/src/Contracts.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ export interface IModule<State> {
2828
* These actions are dispatched immediatly before removing the module from the store
2929
*/
3030
finalActions?: AnyAction[];
31+
32+
/**
33+
* Specifies if the module is retained forever in the store
34+
*/
35+
retained?: boolean;
3136
}
3237

3338
export interface IExtension {

packages/redux-dynamic-modules-core/src/Managers/RefCountedManager.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import { IItemManager } from "../Contracts";
66
*/
77
export function getRefCountedManager<IType extends IItemManager<T>, T>(
88
manager: IType,
9-
equals: (a: T, b: T) => boolean
9+
equals: (a: T, b: T) => boolean,
10+
retained?: (a: T) => boolean // Decides if the item is retained even when the ref count reaches 0
1011
): IType {
11-
let refCounter = getObjectRefCounter<T>(equals);
12+
let refCounter = getObjectRefCounter<T>(equals, retained);
1213
const items = manager.getItems();
1314
// Set initial ref counting
1415
items.forEach(item => refCounter.add(item));

packages/redux-dynamic-modules-core/src/ModuleStore.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,26 +123,27 @@ export function createStore<State>(
123123
applyMiddleware(...extensionMiddleware, middlewareManager.enhancer)
124124
);
125125

126-
const modules = getRefCountedManager(
126+
const moduleManager = getRefCountedManager(
127127
getModuleManager<State>(middlewareManager, extensions),
128-
(a: IModule<any>, b: IModule<any>) => a.id === b.id
128+
(a: IModule<any>, b: IModule<any>) => a.id === b.id,
129+
(a) => a.retained
129130
);
130131

131132
// Create store
132133
const store: IModuleStore<State> = createReduxStore<State, any, {}, {}>(
133-
modules.getReducer,
134+
moduleManager.getReducer,
134135
initialState,
135136
enhancer as any
136137
) as IModuleStore<State>;
137138

138-
modules.setDispatch(store.dispatch);
139+
moduleManager.setDispatch(store.dispatch);
139140

140141
const addModules = (modulesToBeAdded: IModuleTuple) => {
141142
const flattenedModules = flatten(modulesToBeAdded);
142-
modules.add(flattenedModules);
143+
moduleManager.add(flattenedModules);
143144
return {
144145
remove: () => {
145-
modules.remove(flattenedModules);
146+
moduleManager.remove(flattenedModules);
146147
},
147148
};
148149
};
@@ -165,7 +166,7 @@ export function createStore<State>(
165166

166167
store.dispose = () => {
167168
// get all added modules and remove them
168-
modules.dispose();
169+
moduleManager.dispose();
169170
middlewareManager.dispose();
170171
extensions.forEach(p => {
171172
if (p.dispose) {

packages/redux-dynamic-modules-core/src/Utils/RefCounter.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ export interface IRefCounter<T> {
1616

1717
/** Ref counts given object */
1818
export function getObjectRefCounter<T>(
19-
equals: (a: T, b: T) => boolean
19+
equals: (a: T, b: T) => boolean,
20+
retained?: (a: T) => boolean
2021
): IRefCounter<T> {
2122
if (!equals) {
2223
equals = (a, b) => a === b;
2324
}
25+
26+
if(!retained) {
27+
retained = () => false;
28+
}
2429
const objects: T[] = [];
2530
const counts: number[] = [];
2631
return {
@@ -54,12 +59,22 @@ export function getObjectRefCounter<T>(
5459
} else {
5560
count = counts[index] + 1;
5661
}
62+
63+
// If item is retained then keep it for inifinty
64+
if (retained(obj)) {
65+
count = Infinity;
66+
}
67+
5768
counts[index] = count;
5869
},
5970
/**
6071
* Decreases ref count for given T, if refcount reaches to zero removes the T and returns true
6172
*/
6273
remove: (obj: T): boolean => {
74+
if (retained(obj)) {
75+
return false;
76+
}
77+
6378
let index = objects.findIndex(o => o && equals(o, obj));
6479
if (index === -1) {
6580
return false;

packages/redux-dynamic-modules-core/src/__tests__/Utils/RefCounter.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,26 @@ it("tests object ref counter", () => {
4848
expect(refCounter.getCount(a)).toBe(0);
4949
});
5050

51-
function foobar() {}
51+
it("tests object ref counter when objects are retained", () => {
52+
const refCounter = getObjectRefCounter<Function>((a, b) => a === b, () => true);
53+
expect(refCounter.getCount(foobar)).toBe(0);
54+
55+
refCounter.add(a);
56+
expect(refCounter.getCount(a)).toBe(Infinity);
57+
58+
refCounter.add(a);
59+
expect(refCounter.getCount(a)).toBe(Infinity);
60+
61+
expect(refCounter.remove(a)).toBe(false);
62+
expect(refCounter.getCount(a)).toBe(Infinity);
63+
64+
expect(refCounter.remove(a)).toBe(false);
65+
expect(refCounter.getCount(a)).toBe(Infinity);
66+
67+
expect(refCounter.remove(a)).toBe(false);
68+
expect(refCounter.getCount(a)).toBe(Infinity);
69+
});
70+
71+
function foobar() { }
5272

5373
function a() {}

0 commit comments

Comments
 (0)