我有一个带有“导出”按钮的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)))
)
)
);
}
类似:
@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');
您应该使用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'); }) }