【问题标题】:Angular - "TypeError: Cannot freeze" when dispatching an actionAngular - 调度动作时出现“TypeError:无法冻结”
【发布时间】:2019-02-27 20:23:35
【问题描述】:

我正在开发一个使用 ngrx 商店和效果的 Angular 应用程序。我明白了

“类型错误:无法冻结”

从我的组件调度操作时出错。我为文件上传功能编写了它。我认为我正在改变状态,但无法弄清楚在哪里以及如何解决它。 这是我的详细代码:

Actions:

export enum FileUploadActionTypes {
    UploadFile = '[File Upload] Upload File',
    UploadFileSuccess = '[File Upload] Upload File Success',
    UploadFileFailure = '[File Upload] Upload File Failure'
}

export class UploadFile implements Action {
    readonly type = FileUploadActionTypes.UploadFile;

    constructor(public payload: any) {}
}

export class UploadFileSuccess implements Action {
    readonly type = FileUploadActionTypes.UploadFileSuccess;

    constructor(public payload: any) {}
}

export class UploadFileFailure implements Action {
    readonly type = FileUploadActionTypes.UploadFileFailure;

    constructor(public payload: any) {}
}

export type FileUploadActionsUnion = UploadFile | UploadFileSuccess | UploadFileFailure;

Service:

export class FileUploadService {
    constructor(private httpClient: HttpClient) {

    }
    uploadFile(file: any): Observable<any> {
        return this.httpClient.post<any[]>('/api-url/', file);
    }
}

Effect:

@Effect()
uploadFile$ = this.actions$.pipe(
    ofType<UploadFile>(FileUploadActionTypes.UploadFile),
    mergeMap(action => this.fileUploadService.uploadFile(action.payload).pipe(
        map(result => new UploadFileSuccess(result)),
        catchError(error => of(new UploadFileFailure(error)))
    ))
)

Reducer:

export interface State {
    fileUploadSuccessResponse: any,
    fileUploadFailureResponse: any
}

export const initialState = {
    fileUploadSuccessResponse: null,
    fileUploadFailureResponse: null
}

export const getFileUploadSuccessResponse = state => state.fileUploadSuccessResponse;
export const getFileUploadFailureResponse = state => state.fileUploadFailureResponse;

export function reducer(state: State = initialState, action: FileUploadActionsUnion):State {
    switch(action.type) {
        case FileUploadActionTypes.UploadFile: {
            return {
                ...state
            }
        }
        case FileUploadActionTypes.UploadFileSuccess: {
            return {
                ...state,
                fileUploadSuccessResponse: action.payload
            }
        }
        case FileUploadActionTypes.UploadFileFailure: {
            return {
                ...state,
                fileUploadFailureResponse: action.payload
            }
        }
        default: {
            return state;
        }
    }
}

【问题讨论】:

  • payload 长什么样子?

标签: angular ngrx ngrx-store


【解决方案1】:

看来您正在使用ngrx-store-freeze npm 包。此软件包可确保您对商店所做的任何更新都不会直接发生变化。此过程的一部分是将Object.freeze() 应用于您尝试调度的操作的payload 对象。即this.store.dispatch(new UploadFiles(file))

&lt;input type="file"&gt; 控件的默认行为是将其值保存为FileList 对象。因为此对象是原始数据类型,Javascript 会将其视为只读,从而阻止您写入它的属性。这也解释了为什么 Object.freeze() 会失败,因为它无法对只读数据类型应用冻结。

我最近在使用 NGRX 和 &lt;input type="file"&gt; 表单控件时遇到了同样的问题。解决方法是在分派到商店之前将 FileList 克隆到一个新对象中。

onChange(control: FormControl) {
  const primitiveFileList: FileList = control.value;
  const clonedFiles = { ...primitiveFileList };
  this.store.dispatch(new UploadFiles(clonedFiles));
}

如果其他人知道这种方法的任何潜在缺陷,我将不胜感激。

【讨论】:

  • 在我的例子中,只是克隆 FileList 对象删除了length 属性和item() 函数。所以我需要自己给clone加上length属性,以后还要用[i]代替item(i)
猜你喜欢
  • 1970-01-01
  • 2021-02-19
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 2011-11-04
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多