问题描述
我有一个 React Native 应用程序,我想在其中使用 Axios 上传一些文件。
我为文件上传做了一个 mobx-state-tree 存储,每个文件都有自己的 CancelTokenSource
,发送到 Axios 网络调用。
最简单的方法如下所示,销毁商店中的商品,然后使用 beforeDestroy()
钩子取消上传。但这种方法使 mobx-state-tree 在屏幕截图中显示错误。
我还尝试在销毁项目之前显式调用 file.cancelTokenSource.cancel()
。同样的错误。我怀疑 cancel()
返回时操作没有完全取消,但由于它不是异步函数,我无法 await
完成。
当我在没有销毁的情况下调用 cancel()
时,它取消就好了,所以我很确定这是一个时间问题,在 {{1} 之前调用 destroy(file)
过早} 已经自行清理完毕。
在这里做什么?
file-upload-store.ts
cancel()
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
}
}
})