角@ngrx-redux我应该在哪里处理不更改状态的类似export的动作

问题描述 投票:0回答:2

我有一个带有“导出”按钮的APP。单击时,APP从服务器获取一个大文本文件,然后使用HTML5 blob API“另存为”,以便用户可以将其保存到他的磁盘上

为了在调度导出动作中开始导出操作

this.store.dispatch(new scanListsActions.Export(id));

然后通过后端服务器获取文件的“效果”代码来处理此操作。完成后,将调度ExportSuccess操作。

现在,我不想将文件内容存储在商店中,因为它很大,另一方面,我需要视图中的数据才能将其发送给用户。目前,您可以看到我通过reducer代码(如下)将其发送给用户。

通常如何完成?将文件发送给用户的存放位置在哪里?

import * as fileSaver from 'file-saver'; // npm i --save file-saver

export function reducer(state: ScanListsState = initialState, action: ScanListsActions): ScanListsState {
    switch (action.type) {
        case ScanListsActionTypes.Export:
            return {
                ...state,
                loading: true
            };

        case ScanListsActionTypes.ExportSuccess:

       // these 2 lines below send the file to the user (starts a download)
       // where should i put this code. I don't think the reducer is the place for it

            const blob = new Blob([action.payload.data], { type: 'text/plain; charset=utf-8' });
            fileSaver.saveAs(blob, 'destination_list.txt');

            return {
                ...state,
                loading: false,
                error: null
            };

        case ScanListsActionTypes.GeneralFail:
            return {
                ...state,
                loading: false,
                error: action.payload
            };
        default:
            return state;
    }
}

效果代码

@Injectable()
export class ScanListsEffects {

    constructor(private scanListService: ScanListService,
        private actions$: Actions) { }



    @Effect()
    exportScanList$: Observable<Action> = this.actions$.pipe(
        ofType(scanListsActions.ScanListsActionTypes.Export),
        mergeMap((action: scanListsActions.Export) =>
            this.scanListService.getScanList(action.payload).pipe(
                map(sList => (new scanListsActions.ExportSuccess(sList))),
                catchError(err => of(new scanListsActions.GeneralFail(err)))
            )
        )
    );
}
angular ngrx reducers
2个回答
1
投票
您应该进行保存呼叫,就像阅读一样。实际上,您会致电该服务:

类似:

@Effect() fileSaveExportScanList$: Observable<Action> = this.actions$.pipe( ofType(scanListsActions.ScanListsActionTypes.ExportSuccess), mergeMap((action: scanListsActions.ExportSuccess) => this.scanListService.saveScanList(action.payload).pipe( map (() => (new scanListsActions.SaveSuccess())), catchError(err => of(new scanListsActions.GeneralFail(err))) ) ) );

然后进行服务呼叫'saveScanList'

saveScanList(data: any){ const blob = new Blob([data], { type: 'text/plain; charset=utf-8' }); fileSaver.saveAs(list, 'destination_list.txt');


1
投票
您是正确的,您不应该在减速器中这样做(至少我不会这样做)。您应该在组件本身中进行此操作。

您应该使用URL或任何键将action.payload.data存储在化简器中,并对它作出反应。

类似这样的东西:

您的减速器状态应该看起来像:

export interface ScanListsState { url: string; // (I assume string), loading: boolean; error: any; // You can put whatever interface you want }

Reducer中的其他所有内容都很好,但ScanListsActionTypes.ExportSuccess:返回的情况除外:

return { ...state, url: action.payload.data, loading: false, error: null, };

然后在您的组件中

ngOnInit() { this.reactToURLChangesOfExport(); } exportClicked() { this.store.dispatch(new scanListsActions.Export(id)); } reactToURLChangesOfExport() { this.store.pipe( select(YourSelectorForTheSliceOfTheURL), // make a selector that will react to changes to the URL property of the slice of data in the store. // put a takeUntil or however you want to destroy this subscription so it prevents memory leaks ).subscribe(url => { const blob = new Blob([url], { type: 'text/plain; charset=utf-8' }); fileSaver.saveAs(blob, 'destination_list.txt'); }) }

© www.soinside.com 2019 - 2024. All rights reserved.