@@ -10,6 +10,10 @@ import {
10
10
} from './interfaces' ;
11
11
import { openFileDialog } from './helpers/openFileDialog' ;
12
12
import { useValidators } from './validators/useValidators' ;
13
+ import { Validator } from './validators' ;
14
+
15
+ // empty array reference in order to avoid re-renders when no validators are passed as props
16
+ const EMPTY_ARRAY : Validator [ ] = [ ] ;
13
17
14
18
function useFilePicker <
15
19
CustomErrors = unknown ,
@@ -20,16 +24,18 @@ function useFilePicker<
20
24
multiple = true ,
21
25
readAs = 'Text' ,
22
26
readFilesContent = true ,
23
- validators = [ ] ,
27
+ validators = EMPTY_ARRAY ,
24
28
initializeWithCustomParameters,
25
29
} = props ;
26
30
27
31
const [ plainFiles , setPlainFiles ] = useState < File [ ] > ( [ ] ) ;
28
32
const [ filesContent , setFilesContent ] = useState < FileContent < ExtractContentTypeFromConfig < ConfigType > > [ ] > ( [ ] ) ;
29
33
const [ fileErrors , setFileErrors ] = useState < UseFilePickerError < CustomErrors > [ ] > ( [ ] ) ;
30
34
const [ loading , setLoading ] = useState < boolean > ( false ) ;
31
- const { onFilesSelected, onFilesSuccessfullySelected, onFilesRejected, onClear } =
32
- useValidators < ConfigType , CustomErrors > ( props ) ;
35
+ const { onFilesSelected, onFilesSuccessfullySelected, onFilesRejected, onClear } = useValidators <
36
+ ConfigType ,
37
+ CustomErrors
38
+ > ( props ) ;
33
39
34
40
const clear : ( ) => void = useCallback ( ( ) => {
35
41
setPlainFiles ( [ ] ) ;
@@ -42,45 +48,48 @@ function useFilePicker<
42
48
onClear ?.( ) ;
43
49
} , [ clear , onClear ] ) ;
44
50
45
- const parseFile = ( file : FileWithPath ) =>
46
- new Promise < FileContent < ExtractContentTypeFromConfig < ConfigType > > > (
47
- async (
48
- resolve : ( fileContent : FileContent < ExtractContentTypeFromConfig < ConfigType > > ) => void ,
49
- reject : ( reason : UseFilePickerError ) => void
50
- ) => {
51
- const reader = new FileReader ( ) ;
52
-
53
- //availible reader methods: readAsText, readAsBinaryString, readAsArrayBuffer, readAsDataURL
54
- const readStrategy = reader [ `readAs${ readAs } ` as ReaderMethod ] as typeof reader . readAsText ;
55
- readStrategy . call ( reader , file ) ;
56
-
57
- const addError = ( { ...others } : UseFilePickerError ) => {
58
- reject ( { ...others } ) ;
59
- } ;
60
-
61
- reader . onload = async ( ) =>
62
- Promise . all (
63
- validators . map ( validator =>
64
- validator . validateAfterParsing ( props , file , reader ) . catch ( err => Promise . reject ( addError ( err ) ) )
65
- )
66
- )
67
- . then ( ( ) =>
68
- resolve ( {
69
- ...file ,
70
- content : reader . result as string ,
71
- name : file . name ,
72
- lastModified : file . lastModified ,
73
- } as FileContent < ExtractContentTypeFromConfig < ConfigType > > )
51
+ const parseFile = useCallback (
52
+ ( file : FileWithPath ) =>
53
+ new Promise < FileContent < ExtractContentTypeFromConfig < ConfigType > > > (
54
+ async (
55
+ resolve : ( fileContent : FileContent < ExtractContentTypeFromConfig < ConfigType > > ) => void ,
56
+ reject : ( reason : UseFilePickerError ) => void
57
+ ) => {
58
+ const reader = new FileReader ( ) ;
59
+
60
+ //availible reader methods: readAsText, readAsBinaryString, readAsArrayBuffer, readAsDataURL
61
+ const readStrategy = reader [ `readAs${ readAs } ` as ReaderMethod ] as typeof reader . readAsText ;
62
+ readStrategy . call ( reader , file ) ;
63
+
64
+ const addError = ( { ...others } : UseFilePickerError ) => {
65
+ reject ( { ...others } ) ;
66
+ } ;
67
+
68
+ reader . onload = async ( ) =>
69
+ Promise . all (
70
+ validators . map ( validator =>
71
+ validator . validateAfterParsing ( props , file , reader ) . catch ( err => Promise . reject ( addError ( err ) ) )
72
+ )
74
73
)
75
- . catch ( ( ) => { } ) ;
76
-
77
- reader . onerror = ( ) => {
78
- addError ( { name : 'FileReaderError' , readerError : reader . error , causedByFile : file } ) ;
79
- } ;
80
- }
81
- ) ;
74
+ . then ( ( ) =>
75
+ resolve ( {
76
+ ...file ,
77
+ content : reader . result as string ,
78
+ name : file . name ,
79
+ lastModified : file . lastModified ,
80
+ } as FileContent < ExtractContentTypeFromConfig < ConfigType > > )
81
+ )
82
+ . catch ( ( ) => { } ) ;
83
+
84
+ reader . onerror = ( ) => {
85
+ addError ( { name : 'FileReaderError' , readerError : reader . error , causedByFile : file } ) ;
86
+ } ;
87
+ }
88
+ ) ,
89
+ [ props , readAs , validators ]
90
+ ) ;
82
91
83
- const openFilePicker = ( ) => {
92
+ const openFilePicker = useCallback ( ( ) => {
84
93
const fileExtensions = accept instanceof Array ? accept . join ( ',' ) : accept ;
85
94
openFileDialog (
86
95
fileExtensions ,
@@ -156,7 +165,19 @@ function useFilePicker<
156
165
} ,
157
166
initializeWithCustomParameters
158
167
) ;
159
- } ;
168
+ } , [
169
+ props ,
170
+ accept ,
171
+ clear ,
172
+ initializeWithCustomParameters ,
173
+ multiple ,
174
+ onFilesRejected ,
175
+ onFilesSelected ,
176
+ onFilesSuccessfullySelected ,
177
+ parseFile ,
178
+ readFilesContent ,
179
+ validators ,
180
+ ] ) ;
160
181
161
182
return {
162
183
openFilePicker,
0 commit comments