在销毁对象之前取消上传请求使 mobx-state-tree 抛出无法修改 [死] 错误

问题描述

我有一个 React Native 应用程序,我想在其中使用 Axios 上传一些文件

我为文件上传做了一个 mobx-state-tree 存储,每个文件都有自己的 CancelTokenSource,发送到 Axios 网络调用

上传过程中,我尝试取消上传,然后销毁该项目。

最简单的方法如下所示,销毁商店中的商品,然后使用 beforeDestroy() 钩子取消上传。但这种方法使 mobx-state-tree 在屏幕截图中显示错误

我还尝试在销毁项目之前显式调用 file.cancelTokenSource.cancel()。同样的错误。我怀疑 cancel() 返回时操作没有完全取消,但由于它不是异步函数,我无法 await 完成。

当我在没有销毁的情况下调用 cancel() 时,它取消就好了,所以我很确定这是一个时间问题,在 {{1} 之前调用 destroy(file) 过早} 已经自行清理完毕。

在这里做什么?

enter image description here

file-upload-store.ts

cancel()

文件上传.ts

import { destroy,flow,Instance,types } from 'mobx-state-tree'

import { FileUpload,IFileUpload } from '../entities/file-upload/file-upload'
import { getApi } from '../../store-environment'

/**
 * Store for handling the FileUpload
 */
export const FileUploadStore = types
  .model('FileUploadStore')
  .props({
    files: types.array(FileUpload),})
  .actions((self) => {
    const api = getApi(self)

    const add = (uri: string,name: string,type: string,size: number) => {
      const file = FileUpload.create({
        uri,name,type,size,})
      self.files.push(file)
      upload(file)
    }

    const remove = (file: IFileUpload) => {
      destroy(file)
    }

    const cancel = (file: IFileUpload) => {
      // also tried this - with no luck
      // file.cancelTokenSource.cancel()
      destroy(file)
    }

    const upload = flow(function* (file: IFileUpload) {
      file.status = 'pending'
      file.uploadedBytes = 0
      const { uri,type } = file

      try {
        const id = yield api.uploadFile(uri,file.setProgress,file.cancelTokenSource.token)
        file.status = 'completed'
        file.fileUploadId = id
      } catch (error) {
        file.status = 'Failed'
        file.error = error.message
      }
    })

    return {
      afterCreate() {
        // Avoid persistance
        self.files.clear()
      },remove,cancel,retry: upload,add,}
  })

export type IFileUploadStore = Instance<typeof FileUploadStore>

解决方法

您正在销毁 FileUpload 节点并很好地取消了 axios 请求,但是取消请求会引发错误,因此您需要确保您的 FileUpload 节点还活着在您尝试在 catch 中更新它之前。

import { destroy,flow,Instance,types,isAlive } from 'mobx-state-tree'

// ...

const upload = flow(function* (file: IFileUpload) {
  const { uri,name,type } = file

  file.status = "pending"
  file.uploadedBytes = 0

  try {
    const id = yield api.uploadFile(
      uri,type,file.setProgress,file.cancelTokenSource.token
    )

    file.status = "completed"
    file.fileUploadId = id
  } catch (error) {
    if (isAlive(file)) {
      file.status = "failed"
      file.error = error.message
    }
  }
})