Skip to content

Commit 304b83d

Browse files
committed
types exported
1 parent 3638a82 commit 304b83d

File tree

3 files changed

+177
-173
lines changed

3 files changed

+177
-173
lines changed

src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { useUploader } from './use-uploader';

src/hooks/use-uploader.ts

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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+
};

src/index.ts

Lines changed: 3 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,3 @@
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

Comments
 (0)