在销毁对象之前取消上传请求会使 mobx-state-tree 抛出 Cannot modify [dead] 错误
Cancelling upload request before destroying object makes mobx-state-tree throw Cannot modify [dead] errors
我有一个 React Native 应用程序,我想在其中使用 Axios 上传一些文件。
我做了一个文件上传的mobx-state-tree存储,每个文件都有自己的CancelTokenSource
,发送到axios网络调用
上传正在进行时,我尝试取消上传,然后销毁该项目。
最简单的方法就像我在下面展示的那样,通过销毁商店中的物品,然后有一个取消上传的 beforeDestroy()
挂钩。但是这种方法使 mobx-state-tree 在屏幕截图中显示错误。
我也试过在销毁项目之前明确调用 file.cancelTokenSource.cancel()
。同样的错误。我怀疑 cancel()
returns 时操作没有完全取消,但由于它不是异步函数,我无法 await
它完成。
当我只是调用 cancel()
而不破坏时,它取消得很好,所以我很确定这是一个时间问题,destroy(file)
在 [= 之前被调用得太早了15=] 已自行清理。
在这里做什么?
文件上传-store.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, name, type } = file
try {
const id = yield api.uploadFile(uri, name, type, 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>
文件-upload.ts
import { Instance, SnapshotIn, types } from 'mobx-state-tree'
import { CancelToken } from 'apisauce'
/**
* FileUpload contains the particular data of a file, and some flags describing its status.
*/
export const FileUpload = types
.model('FileUpload')
.props({
name: types.string,
type: types.string,
uri: types.string,
size: types.number,
// set if an arror occours
error: types.maybe(types.string),
status: types.optional(types.enumeration(['pending', 'completed', 'failed']), 'pending'),
// updated by progressCallback
uploadedBytes: types.optional(types.number, 0),
// assigned when response from backend is received
fileUploadId: types.maybe(types.string),
})
.volatile(() => ({
cancelTokenSource: CancelToken.source(),
}))
.actions((self) => ({
setProgress(event: ProgressEvent) {
self.uploadedBytes = event.loaded
},
beforeDestroy() {
self.cancelTokenSource?.cancel()
},
}))
export interface IFileUpload extends Instance<typeof FileUpload> {}
// SnapshotIn, used for creating input to store: {Model}.create({})
export interface IFileUploadSnapshotIn extends SnapshotIn<typeof FileUpload> {}
你正在销毁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,
name,
type,
file.setProgress,
file.cancelTokenSource.token
)
file.status = "completed"
file.fileUploadId = id
} catch (error) {
if (isAlive(file)) {
file.status = "failed"
file.error = error.message
}
}
})
我有一个 React Native 应用程序,我想在其中使用 Axios 上传一些文件。
我做了一个文件上传的mobx-state-tree存储,每个文件都有自己的CancelTokenSource
,发送到axios网络调用
上传正在进行时,我尝试取消上传,然后销毁该项目。
最简单的方法就像我在下面展示的那样,通过销毁商店中的物品,然后有一个取消上传的 beforeDestroy()
挂钩。但是这种方法使 mobx-state-tree 在屏幕截图中显示错误。
我也试过在销毁项目之前明确调用 file.cancelTokenSource.cancel()
。同样的错误。我怀疑 cancel()
returns 时操作没有完全取消,但由于它不是异步函数,我无法 await
它完成。
当我只是调用 cancel()
而不破坏时,它取消得很好,所以我很确定这是一个时间问题,destroy(file)
在 [= 之前被调用得太早了15=] 已自行清理。
在这里做什么?
文件上传-store.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, name, type } = file
try {
const id = yield api.uploadFile(uri, name, type, 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>
文件-upload.ts
import { Instance, SnapshotIn, types } from 'mobx-state-tree'
import { CancelToken } from 'apisauce'
/**
* FileUpload contains the particular data of a file, and some flags describing its status.
*/
export const FileUpload = types
.model('FileUpload')
.props({
name: types.string,
type: types.string,
uri: types.string,
size: types.number,
// set if an arror occours
error: types.maybe(types.string),
status: types.optional(types.enumeration(['pending', 'completed', 'failed']), 'pending'),
// updated by progressCallback
uploadedBytes: types.optional(types.number, 0),
// assigned when response from backend is received
fileUploadId: types.maybe(types.string),
})
.volatile(() => ({
cancelTokenSource: CancelToken.source(),
}))
.actions((self) => ({
setProgress(event: ProgressEvent) {
self.uploadedBytes = event.loaded
},
beforeDestroy() {
self.cancelTokenSource?.cancel()
},
}))
export interface IFileUpload extends Instance<typeof FileUpload> {}
// SnapshotIn, used for creating input to store: {Model}.create({})
export interface IFileUploadSnapshotIn extends SnapshotIn<typeof FileUpload> {}
你正在销毁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,
name,
type,
file.setProgress,
file.cancelTokenSource.token
)
file.status = "completed"
file.fileUploadId = id
} catch (error) {
if (isAlive(file)) {
file.status = "failed"
file.error = error.message
}
}
})