ngrx: общие редукторы - PullRequest
0 голосов
/ 02 мая 2018

У меня есть приложение, в котором есть несколько магазинов с одинаковыми функциями редуктора. Я попытался сделать общий редуктор, и он работал нормально.

общие настройки редуктора:

interface State<T> {
    itemList : T[]
}

const initialState: State<any> = {
    itemList: []
}


const createReducer = <T>(type: string) => {
    return <T>(state = initialState, action: any): State<T> => {
        switch (action.type) {
            case types.get(type).Add:
                return {
                    ...state,
                    itemList: [...state.itemList, action.payload]
                }

            case types.get(type).AddList:
                return {
                    ...state,
                    itemList: [...state.itemList, ...action.payload]
                };

            default:
                return state;
        }
    }
}

Тогда я бы комбинировал редукторы следующим образом:

export const reducers: ActionReducerMap<AppState> = {
    vehiculeState: createReducer<Vehicule>('vehicule'),
    rentState: createReducer<Rent>('rent'),
    clientState : createReducer<Client>('client'),
    companionState : createReducer<Client>('companion'),
    paymentState : createReducer<Payment>('payment'),
    notificationState : createReducer<Notification>('notification'),
    employeeState : createReducer<Employee>('employee')
}

Проблема в том, что при переходе в общий режим мне пришлось бы переписать большую часть моего приложения, поскольку я уже создал несколько редукторов с состояниями, которые содержат свойства с именами (clientList, vehiculeList, ...) , а имя свойства itemList не очень информативно. Поэтому мой вопрос заключается в том, как перейти в общий режим и сохранить свойства состояния такими, какие они есть?

Пример токовых редукторов:

export function rentReducer(state = initialState, action: rentActions.RentActions): State {
    switch(action.type){
        case rentActions.ADD_RENT:
        return{
            ...state,
            rentList : [...state.rentList, action.payload]
        }

        case rentActions.ADD_RENT_LIST:
        return {
            ...state,
            rentList : [...state.rentList, ...action.payload]
        };


        default:
        return state;
    }

}

1 Ответ

0 голосов
/ 02 мая 2018

Вы можете использовать строку для представления имени свойства itemList и использовать сопоставленные типы, чтобы превратить эту строку в безопасное свойство типа для типа State. Одним из недостатков является то, что использование оператора распространения не поддерживается для отображаемых типов, но мы можем получить аналогичный эффект с Object.assign

// We add an extra parameter to State that will be the property name passed in as a string literal type
// So State<Vehicle, 'vehicleList'> will be a type equivalent to { vehicleList : Vehicle[] }
type  State<T, TListName extends string> = {
    [P in TListName] : T[]
}

// We create a function that creates the initial state by initializing an object with an empty array and the given property name
const initialState = <T, TListName extends string>(itemListName: TListName): State<T, TListName> => {
    let result = {} as State<any, TListName>;
    result[itemListName] = [];
    return result;
};

// Since we can't use the spread operator, we create a new function that updates the state 
// state will be the original state, 
// itemListName the property name which contains the list 
// newItems will be the new list 
const updateState = <T, TListName extends string>(args: { state: State<T, TListName>, itemListName: TListName, newItems: T[] }): State<T, TListName> => {
    return Object.assign({},args.state, {
        [args.itemListName] : args.newItems
    });
}
// We will use a 2 function approach for the createReducer function
// We do this in order to be able to specify the item type  (T) explicitly,
// but not have to specify the string literal type TListName and let it be inferred 
const createReducer = <T>(type: string) => <TListName extends string>(itemListName: TListName) => {
    return (state = initialState<T, TListName>(itemListName), action: any): State<T, TListName> => {
        switch (action.type) {
            case types.get(type).Add:
                return updateState({
                    state,
                    itemListName,
                    newItems: [...state[itemListName], <T>action.payload]
                });

            case types.get(type).AddList:
                return updateState({
                    state,
                    itemListName,
                    newItems: [...state[itemListName], ...<T[]>action.payload]
                })

            default:
                return state;
        }
    }
}
export const reducers = {
    vehiculeState: createReducer<Vehicule>('vehicule')('vehiculeItems'),
    rentState: createReducer<Rent>('rent')('rentItems'),
    clientState : createReducer<Client>('client')('clientItems'),
    companionState : createReducer<Client>('companion')('companionItems'),
    paymentState : createReducer<Payment>('payment')('paymentItems'),
    notificationState : createReducer<Notification>('notification')('notificationItems'),
    employeeState : createReducer<Employee>('employee')('employeeItems'),
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...