Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 1x 1x 4x 3x 1x 1x 1x 4x 6x 1x 5x 5x | import { createSlice, PayloadAction, SliceCaseReducers, ValidateSliceCaseReducers } from '@reduxjs/toolkit';
export interface TreeState<T> {
root?: string;
childMap: { [id: string]: string[] };
parentMap: { [id: string]: string };
nodeMap: { [id: string]: T };
}
export interface AppendChildPayload<T> {
parent?: string;
id: string;
data: T;
}
/**
* Generic createSlice wrapper for tree state management
* @param name - slice name
* @param initialState
* @param reducers - extended reducers upon instantiation
*/
export const createGenericSlice = <
T,
Reducers extends SliceCaseReducers<TreeState<T>>
>({
name = '',
initialState,
reducers
}: {
name: string
initialState: TreeState<T>
reducers: ValidateSliceCaseReducers<TreeState<T>, Reducers>
}) => {
return createSlice({
name,
initialState,
reducers: {
appendChild(state: TreeState<T>, action: PayloadAction<AppendChildPayload<T>>) {
if (action.payload.parent === undefined) {
// no parent == root
state.root = action.payload.id;
} else {
Iif (!state.childMap[action.payload.parent]) {
state.childMap[action.payload.parent] = [];
}
state.childMap[action.payload.parent].push(action.payload.id);
state.parentMap[action.payload.id] = action.payload.parent;
}
state.nodeMap[action.payload.id] = action.payload.data;
},
...reducers
}
})
}
export function selectNode<T> (state: TreeState<T>, id: string): T | undefined {
return state.nodeMap[id];
}
const emptyList: [] = [];
export function selectChildren (state: TreeState<unknown>, id: string): string[] {
return state.childMap[id] || emptyList; // using [] instead of 'emptyList' will invoke unnecessary updates
}
export function selectRoot(state: TreeState<unknown>): string | undefined {
return state.root;
}
|