Как предотвратить изменение наблюдаемой излучаемой величины - PullRequest
0 голосов
/ 19 апреля 2019

Я подписываюсь на наблюдаемый и снимаю новый элемент в результирующий массив, который изменяет данные.Как я могу предотвратить мутацию данных на уровне сервиса, создав исключение, если кто-то пытается изменить данные, а не делать глубокое копирование?

У меня есть угловой сервис для получения списка состояний из API на основе кода страны.Это одноэлементный сервис, означающий, что один и тот же экземпляр используется несколькими модулями и их компонентами.Я кеширую ответ с ShareReplay ().Когда в моем компоненте я подписываюсь на наблюдаемое и изменяю результат (отменяя перенос нового значения в массив), кэшированные данные видоизменяются.Прямо сейчас я делаю глубокое копирование результата, и это хорошо, но я хочу, чтобы моя наблюдаемая выдавала исключение, если кто-то пытается использовать сервис и изменяет исходное значение вместо глубокого копирования.Я также пытался заставить сервис возвращать глубокую копию наблюдаемого, но это не сработало, думаю, lodash не знает, как глубоко копировать наблюдаемые, если только я не отказываюсь от shareReplay (), не реализую свой собственный ReplaySubject на уровне сервиса и не возвращаю метод next ()может быть, глубокая копия испущенного значения?

Сервис

@Injectable()
export class StatesService {

    private states$: Observable<State[]> = null;

    constructor(private _http: HttpService) {}

    getStatesFromCountry(countryCode3: string, freshData: boolean = false): Observable<State[]> {
        let code = Object.keys(CountryEnum)
            .filter((key: any) => isNaN(key))
            .find(key => key === countryCode3.toUpperCase());

        if(!code) return Observable.throw("Country Code was not recognized. Make sure it exists in CountryEnum.");

        let url: string = `api/states?country=${countryCode3}`;

        if (freshData) return this.getStates(url);

        return this.states$ ? this.states$ : this.states$ = this.getStates(url).shareReplay(1);
    }

    private getStates(url: string): Observable<State[]> {
        return this._http.get(url)
            .map(response => response)
            .catch(error => Observable.throw(<ApiError>JSON.parse(error)));
    }

}

Компонент

    private loadStates(): Subscription {
        const usaStates$ = this._statesService.getStatesFromCountry(CountryEnum[CountryEnum.USA]);
        const canStates$ = this._statesService.getStatesFromCountry(CountryEnum[CountryEnum.CAN]);

        return Observable.forkJoin(usaStates$, canStates$).subscribe(
            ([usaStates, canStates]) => {
                this.statesList = _.cloneDeep(usaStates.concat(canStates));

                //Here if I unshift without doing deep copy first, other 
                //components that are using this shared service will now 
                //receive a mutated array of states

                this.statesList.unshift(<State>{id: null, code: 'All'});
            },
            error => { ApiError.onError(error, this._notificationService, this._loaderService); }
        );
    }

1 Ответ

1 голос
/ 19 апреля 2019

Вы должны иметь возможность использовать Object.freeze для значения (где-то).

const test = [1,2,3,4];
Object.freeze(test);

test.unshift(0); // error will be thrown

Невозможно добавить свойство 5, объект не является расширяемым

...