Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | 2x 22x 22x 8x 8x 8x 8x 7x 7x 1x 1x 2x 7x 1x 7x 2x 2x 2x 2x 2x 2x 2x 2x 7x 1x 7x 1x 7x 22x | import { useState } from "react";
type Headers = {
[key: string]: any;
};
type RequestOptions = {
method: string;
url: string;
headers?: Headers;
body: Document | BodyInit | null | undefined;
};
type BeforeRequestProps = {
xhr: XMLHttpRequest;
files: FileList;
};
type BeforeRequest = (
props: BeforeRequestProps
) => Promise<RequestOptions | undefined> | RequestOptions | undefined;
type UploadProps = {
files: FileList;
};
type UseUploadState<Response> = {
loading: boolean;
done: boolean;
data?: Response;
error?: ProgressEvent;
xhr?: XMLHttpRequest;
responseHeaders?: Headers;
progress?: number;
};
type UseUploadResults<Response> = [
(props: UploadProps) => void,
UseUploadState<Response>
];
export const useUpload = <Response = any>(
beforeRequest: BeforeRequest
): UseUploadResults<Response> => {
let [state, setState] = useState<UseUploadState<Response>>({
loading: false,
done: false,
});
const upload = async ({ files }: UploadProps) => {
setState({ loading: true, done: false });
const xhr = new XMLHttpRequest();
let options = await beforeRequest({ xhr, files });
// bail out if you return undefined from options
if (!options) return setState({ loading: false, done: false });
xhr.open(options.method, options.url);
/*
Helper method for setting headers on an xhr request, one of the only
extra features of this hook
*/
if (options.headers) {
let headers = options.headers;
Object.keys(options.headers).forEach((header) =>
xhr.setRequestHeader(header, headers[header])
);
}
/*
XHR Listeners
*/
xhr.upload.addEventListener("progress", (event) => {
setState((state) => ({
...state,
progress: Math.round((event.loaded / event.total) * 100),
}));
});
xhr.addEventListener("load", () => {
let data;
try {
data = JSON.parse(xhr.response);
} catch (e) {
data = xhr.response;
}
let responseHeaders = xhr
.getAllResponseHeaders()
.trim()
.split(/[\r\n]+/)
.map((line) => line.split(": "))
.reduce((acc: Headers, [header, value]) => {
acc[header] = value;
return acc;
}, {});
setState({ data, loading: false, xhr, responseHeaders, done: true });
});
xhr.addEventListener("error", (error) => {
setState({ error, xhr, loading: false, done: true });
});
xhr.addEventListener("abort", (error) => {
setState({ error, xhr, loading: false, done: true });
});
/*
send the request!
*/
xhr.send(options.body);
};
return [upload, state];
};
|