redux 可通过 axios onProgress 观察
redux observable with axios onProgress
我正在创建一个上传功能,它将在 React Redux and Redux-observable, and i use axios 中向客户端显示进度条以向 AWS S3 发出放置请求。
我的epics如下
...
function uploadFile(mimetype, url, file) {
const config = {
headers: {
'Content-Type': mimetype,
},
onUploadProgress(progress) {
const percentCompleted = Math.round((progress.loaded * 100) / progress.total)
uploadProgress(percentCompleted)
},
}
axiosRetry(axios, { retries: 3 })
return axios.put(url, file[0], config)
}
export const uploadEpic = (action$, store) => action$
.ofType(SIGNED_URL_SUCCESS)
.mergeMap(() => {
const file = store.getState().File.droppedFile
const mimetype = file[0].type
const { url } = store.getState().SignedUrl
const { fileData } = store.getState().Upload
return of(uploadFile(mimetype, url.data, file))
.concatMap(() => {
const uploadedData = {
url: fileData.url,
thumbUrl: `${fileData.folder}/${fileData.filename}-00001.png`,
}
return [
upload(uploadedData),
uploadSuccess(),
]
})
.catch(error => of(uploadFailure(error)))
})
export default uploadEpic
上传似乎有效,因为我收到一封 AWS SNS 电子邮件,告知它已完成,但我似乎看不到它正在更新我的上传减速器中的 Upload.progress 状态。
我使用 axios 的原因很特别,因为它的 axios-retry
和 onUploadProgress
,因为我似乎找不到使用 universal-rx-request[=15 执行 onProgress 的示例=]
大概有两个问题
- 我如何使用 axios 实现此目的
- 我如何使用 universal-rx-request
实现此目的
多亏了这个
我最终完全没有使用 axios
我用它工作了
import { of } from 'rxjs/observable/of'
import { Subject } from 'rxjs/Subject'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/observable/dom/ajax'
import { SIGNED_URL_SUCCESS } from 'ducks/SignedUrl'
import {
upload,
uploadIsLoading,
uploadSuccess,
uploadFailure,
uploadProgress,
} from 'ducks/Upload'
export const uploadEpic = (action$, store) => action$
.ofType(SIGNED_URL_SUCCESS)
.mergeMap(() => {
const file = store.getState().File.droppedFile
const mimetype = file[0].type
const { url } = store.getState().SignedUrl
const { fileData } = store.getState().Upload
const progressSubscriber = new Subject()
const request = Observable.ajax({
method: 'PUT',
url: url.data,
body: file[0],
headers: {
'Content-Type': mimetype,
},
progressSubscriber,
})
const requestObservable = request
.concatMap(() => {
const uploadedData = {
...
}
return [
upload(uploadedData),
uploadIsLoading(false),
uploadSuccess(),
]
})
.catch(error => of(uploadFailure(error)))
return progressSubscriber
.map(e => ({ percentage: (e.loaded / e.total) * 100 }))
.map(data => uploadProgress(data.percentage))
.merge(requestObservable)
})
更新: on rxjs 6 the merge operators is deprecated,因此如果您使用的是 rxjs 6,请将上面的代码更改为
// some/lib/folder/uploader.js
import { of, merge } from 'rxjs' // import merge here
import { ajax } from 'rxjs/ajax'
import { map, catchError } from 'rxjs/operators' // instead of here
import { Subject } from 'rxjs/Subject'
export function storageUploader(...args) {
const progressSubscriber = new Subject()
const request = ajax({...someRequestOptions})
.pipe(
map(() => success()),
catchError((error) => of(failure(error))),
)
const subscriber = progressSubscriber
.pipe(
map((e) => ({ percentage: (e.loaded / e.total) * 100 })),
map((upload) => progress(upload.percentage)),
catchError((error) => of(failure(error))),
)
return merge(subscriber, request) // merge both like this, instead of chaining the request on progressSubscriber
}
//the_epic.js
export function uploadEpic(action$, state$) {
return action$
.pipe(
ofType(UPLOAD),
mergeMap((someUploadOptions) => uploaderLib(
{ ...someUploadOptions },
actionSuccess,
actionFailure,
actionProgress,
)),
catchError((error) => of(actionFailure(error))),
)
}
我正在创建一个上传功能,它将在 React Redux and Redux-observable, and i use axios 中向客户端显示进度条以向 AWS S3 发出放置请求。
我的epics如下
...
function uploadFile(mimetype, url, file) {
const config = {
headers: {
'Content-Type': mimetype,
},
onUploadProgress(progress) {
const percentCompleted = Math.round((progress.loaded * 100) / progress.total)
uploadProgress(percentCompleted)
},
}
axiosRetry(axios, { retries: 3 })
return axios.put(url, file[0], config)
}
export const uploadEpic = (action$, store) => action$
.ofType(SIGNED_URL_SUCCESS)
.mergeMap(() => {
const file = store.getState().File.droppedFile
const mimetype = file[0].type
const { url } = store.getState().SignedUrl
const { fileData } = store.getState().Upload
return of(uploadFile(mimetype, url.data, file))
.concatMap(() => {
const uploadedData = {
url: fileData.url,
thumbUrl: `${fileData.folder}/${fileData.filename}-00001.png`,
}
return [
upload(uploadedData),
uploadSuccess(),
]
})
.catch(error => of(uploadFailure(error)))
})
export default uploadEpic
上传似乎有效,因为我收到一封 AWS SNS 电子邮件,告知它已完成,但我似乎看不到它正在更新我的上传减速器中的 Upload.progress 状态。
我使用 axios 的原因很特别,因为它的 axios-retry
和 onUploadProgress
,因为我似乎找不到使用 universal-rx-request[=15 执行 onProgress 的示例=]
大概有两个问题
- 我如何使用 axios 实现此目的
- 我如何使用 universal-rx-request 实现此目的
多亏了这个
我最终完全没有使用 axios
我用它工作了
import { of } from 'rxjs/observable/of'
import { Subject } from 'rxjs/Subject'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/observable/dom/ajax'
import { SIGNED_URL_SUCCESS } from 'ducks/SignedUrl'
import {
upload,
uploadIsLoading,
uploadSuccess,
uploadFailure,
uploadProgress,
} from 'ducks/Upload'
export const uploadEpic = (action$, store) => action$
.ofType(SIGNED_URL_SUCCESS)
.mergeMap(() => {
const file = store.getState().File.droppedFile
const mimetype = file[0].type
const { url } = store.getState().SignedUrl
const { fileData } = store.getState().Upload
const progressSubscriber = new Subject()
const request = Observable.ajax({
method: 'PUT',
url: url.data,
body: file[0],
headers: {
'Content-Type': mimetype,
},
progressSubscriber,
})
const requestObservable = request
.concatMap(() => {
const uploadedData = {
...
}
return [
upload(uploadedData),
uploadIsLoading(false),
uploadSuccess(),
]
})
.catch(error => of(uploadFailure(error)))
return progressSubscriber
.map(e => ({ percentage: (e.loaded / e.total) * 100 }))
.map(data => uploadProgress(data.percentage))
.merge(requestObservable)
})
更新: on rxjs 6 the merge operators is deprecated,因此如果您使用的是 rxjs 6,请将上面的代码更改为
// some/lib/folder/uploader.js
import { of, merge } from 'rxjs' // import merge here
import { ajax } from 'rxjs/ajax'
import { map, catchError } from 'rxjs/operators' // instead of here
import { Subject } from 'rxjs/Subject'
export function storageUploader(...args) {
const progressSubscriber = new Subject()
const request = ajax({...someRequestOptions})
.pipe(
map(() => success()),
catchError((error) => of(failure(error))),
)
const subscriber = progressSubscriber
.pipe(
map((e) => ({ percentage: (e.loaded / e.total) * 100 })),
map((upload) => progress(upload.percentage)),
catchError((error) => of(failure(error))),
)
return merge(subscriber, request) // merge both like this, instead of chaining the request on progressSubscriber
}
//the_epic.js
export function uploadEpic(action$, state$) {
return action$
.pipe(
ofType(UPLOAD),
mergeMap((someUploadOptions) => uploaderLib(
{ ...someUploadOptions },
actionSuccess,
actionFailure,
actionProgress,
)),
catchError((error) => of(actionFailure(error))),
)
}