1- import * as React from 'react' ;
2- import * as Utils from './utils' ;
3- import axios from 'axios' ;
4- import { Failed , Task , Uploaded , Uploader , Uploading , UploadParams } from './types' ;
5-
6- type AbortMap = {
7- [ key : string ] : AbortController
8- }
9-
10- export function useUploader < Result = any > ( {
11- url, fieldname, method, headers, separately = false
12- } : UploadParams ) : Uploader < Result > {
13-
14- const mounted = React . useRef < boolean > ( false ) ;
15- const abortMap = React . useRef < AbortMap > ( { } ) ;
16- const [ tasks , setTasks ] = React . useState < Task < Result > [ ] > ( [ ] ) ;
17-
18-
19- React . useEffect ( ( ) => {
20- mounted . current = true ;
21- return ( ) => {
22- mounted . current = false ;
23- }
24- } , [ mounted ] )
25-
26- const updateTask = ( id : string , newData : Partial < Task < Result > > ) => {
27- if ( ! mounted . current ) return ;
28- setTasks ( tasks => tasks . map ( t => {
29- if ( t . id === id ) {
30- return { ...t , ...newData } ;
31- }
32- return t ;
33- } ) ) ;
34- }
35-
36- const setAbort = ( id : string , controller : AbortController ) : void => {
37- abortMap . current [ id ] = controller ;
38- }
39-
40- const getAbort = ( id : string ) : AbortController => {
41- return abortMap . current [ id ] ;
42- }
43-
44- const uploadFile = async ( { id, source, meta } : Task < Result > ) => {
45-
46- const controller = new AbortController ( ) ;
47- setAbort ( id , controller ) ;
48- const defaultConfig = {
49- signal : controller . signal ,
50- onUploadProgress : ( { total, loaded } : ProgressEvent ) => {
51- const progress = Math . round ( ( loaded / total ) * 100 ) ;
52- updateTask ( id , {
53- progress,
54- status : Uploading
55- } ) ;
56- }
57- } ;
58- try {
59- const form = new FormData ( ) ;
60-
61- for ( let key in meta ) {
62- if ( meta . hasOwnProperty ( key ) ) {
63- form . append ( `${ key } ` , meta [ key ] ) ;
64- }
65- }
66-
67- if ( Array . isArray ( source ) ) {
68- for ( let file of source ) {
69- form . append ( `${ fieldname } ` , file ) ;
70- }
71- }
72- else form . append ( `${ fieldname } ` , source ) ;
73-
74-
75- const res = await axios . request ( {
76- ...defaultConfig ,
77- ...{ url, method, headers, data : form } ,
78- } )
79-
80- updateTask ( id , {
81- status : Uploaded , result : {
82- httpStatus : res . status ,
83- responseData : res . data as Result
84- }
85- } ) ;
86-
87- } catch ( error ) {
88- const { response } : any = error ;
89- if ( response ) {
90- updateTask ( id , {
91- status : Failed , result : {
92- httpStatus : response ?. status ,
93- responseData : response ?. data as Result
94- }
95- } ) ;
96- }
97- }
98- }
99-
100-
101- const start = (
102- source : File | File [ ] | FileList ,
103- meta ?: { [ key : string ] : any } ,
104- ) => {
105- // return if null or undefined
106- if ( ! source ) return ;
107-
108- let fileList : File [ ] = [ ] ;
109- if ( source instanceof File ) {
110- fileList . push ( source ) ;
111- }
112- if ( source instanceof FileList ) {
113- fileList = Array . from ( source ) ; // converts to array if FileList
114- }
115-
116- if ( ! fileList . length ) return ;
117-
118- if ( separately ) {
119- fileList . map ( ( file : File ) => {
120- const newTask : Task < Result > = {
121- id : Utils . nextId ( ) ,
122- source : file ,
123- progress : 0 ,
124- status : Uploading ,
125- formattedSize : Utils . formatFileSize ( file . size ) ,
126- meta
127- }
128- setTasks ( prevData => [ ...prevData , newTask ] ) ;
129- uploadFile ( newTask )
130- } )
131- }
132- else {
133-
134- let filesSize : number = 0 ;
135- for ( const file of fileList ) {
136- filesSize = filesSize + file . size ;
137- }
138-
139- const newTask : Task < Result > = {
140- id : Utils . nextId ( ) ,
141- source : fileList ,
142- progress : 0 ,
143- status : Uploading ,
144- formattedSize : Utils . formatFileSize ( filesSize ) ,
145- meta
146- }
147- setTasks ( prevData => [ ...prevData , newTask ] ) ;
148- uploadFile ( newTask )
149- }
150-
151- }
152-
153-
154- const retry = ( id : string ) => {
155- const targetTask = tasks . find ( ( task : Task < Result > ) => task . id . includes ( id ) ) ;
156- if ( targetTask ) {
157- uploadFile ( targetTask ) ;
158- }
159- }
160-
161- const remove = ( id : string ) => {
162- setTasks ( ( prevData : Task < Result > [ ] ) => prevData . filter ( ( task : Task < Result > ) => task . id !== id ) ) ;
163- const controller = getAbort ( id ) ;
164- if ( controller ) controller . abort ( )
165- }
166-
167- const stop = ( id : string ) => {
168- const controller = getAbort ( id ) ;
169- if ( controller ) controller . abort ( )
170- }
171-
172- return [ tasks , { start, stop, retry, remove } ] ;
173- } ;
1+ import { useUploader } from './hooks' ;
2+ export * from './types' ;
3+ export { useUploader } ;
0 commit comments