|
1 |
| -import React, { ChangeEvent, Component } from "react"; |
| 1 | +import React, { ChangeEvent, useCallback, useMemo, useState } from "react"; |
2 | 2 |
|
3 |
| -import { dataURItoBlob, shouldRender, WidgetProps } from "@rjsf/utils"; |
| 3 | +import { dataURItoBlob, WidgetProps } from "@rjsf/utils"; |
4 | 4 |
|
5 | 5 | function addNameToDataURL(dataURL: string, name: string) {
|
6 | 6 | if (dataURL === null) {
|
@@ -81,81 +81,63 @@ function extractFileInfo(dataURLs: string[]) {
|
81 | 81 | });
|
82 | 82 | }
|
83 | 83 |
|
84 |
| -type FileWidgetStateType = { |
85 |
| - values: any[]; |
86 |
| - filesInfo: FileInfoType[]; |
87 |
| -}; |
88 |
| - |
89 | 84 | /**
|
90 | 85 | * The `FileWidget` is a widget for rendering file upload fields.
|
91 | 86 | * It is typically used with a string property with data-url format.
|
92 | 87 | */
|
93 |
| -class FileWidget<T, F> extends Component< |
94 |
| - WidgetProps<T, F>, |
95 |
| - FileWidgetStateType |
96 |
| -> { |
97 |
| - constructor(props: WidgetProps<T, F>) { |
98 |
| - super(props); |
99 |
| - const { value } = props; |
100 |
| - const values = Array.isArray(value) ? value : [value]; |
101 |
| - this.state = { values, filesInfo: extractFileInfo(values) }; |
102 |
| - } |
103 |
| - |
104 |
| - shouldComponentUpdate( |
105 |
| - nextProps: WidgetProps<T, F>, |
106 |
| - nextState: FileWidgetStateType |
107 |
| - ): boolean { |
108 |
| - return shouldRender(this, nextProps, nextState); |
109 |
| - } |
| 88 | +function FileWidget<T, F>({ |
| 89 | + multiple, |
| 90 | + id, |
| 91 | + readonly, |
| 92 | + disabled, |
| 93 | + onChange, |
| 94 | + value, |
| 95 | + autofocus = false, |
| 96 | + options, |
| 97 | +}: WidgetProps<T, F>) { |
| 98 | + const extractedFilesInfo = useMemo( |
| 99 | + () => |
| 100 | + Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value]), |
| 101 | + [value] |
| 102 | + ); |
| 103 | + const [filesInfo, setFilesInfo] = |
| 104 | + useState<FileInfoType[]>(extractedFilesInfo); |
110 | 105 |
|
111 |
| - onChange = (event: ChangeEvent<HTMLInputElement>) => { |
112 |
| - const { multiple, onChange } = this.props; |
113 |
| - if (!event.target.files) { |
114 |
| - return; |
115 |
| - } |
116 |
| - processFiles(event.target.files).then((filesInfo) => { |
117 |
| - const state = { |
118 |
| - values: filesInfo.map((fileInfo) => fileInfo.dataURL), |
119 |
| - filesInfo, |
120 |
| - }; |
121 |
| - this.setState(state, () => { |
| 106 | + const handleChange = useCallback( |
| 107 | + (event: ChangeEvent<HTMLInputElement>) => { |
| 108 | + if (!event.target.files) { |
| 109 | + return; |
| 110 | + } |
| 111 | + processFiles(event.target.files).then((filesInfoEvent) => { |
| 112 | + setFilesInfo(filesInfoEvent); |
| 113 | + const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL); |
122 | 114 | if (multiple) {
|
123 |
| - onChange(state.values); |
| 115 | + onChange(newValue); |
124 | 116 | } else {
|
125 |
| - onChange(state.values[0]); |
| 117 | + onChange(newValue[0]); |
126 | 118 | }
|
127 | 119 | });
|
128 |
| - }); |
129 |
| - }; |
| 120 | + }, |
| 121 | + [multiple, onChange] |
| 122 | + ); |
130 | 123 |
|
131 |
| - render() { |
132 |
| - const { |
133 |
| - multiple, |
134 |
| - id, |
135 |
| - readonly, |
136 |
| - disabled, |
137 |
| - autofocus = false, |
138 |
| - options, |
139 |
| - } = this.props; |
140 |
| - const { filesInfo } = this.state; |
141 |
| - return ( |
142 |
| - <div> |
143 |
| - <p> |
144 |
| - <input |
145 |
| - id={id} |
146 |
| - type="file" |
147 |
| - disabled={readonly || disabled} |
148 |
| - onChange={this.onChange} |
149 |
| - defaultValue="" |
150 |
| - autoFocus={autofocus} |
151 |
| - multiple={multiple} |
152 |
| - accept={options.accept ? String(options.accept) : undefined} |
153 |
| - /> |
154 |
| - </p> |
155 |
| - <FilesInfo filesInfo={filesInfo} /> |
156 |
| - </div> |
157 |
| - ); |
158 |
| - } |
| 124 | + return ( |
| 125 | + <div> |
| 126 | + <p> |
| 127 | + <input |
| 128 | + id={id} |
| 129 | + type="file" |
| 130 | + disabled={readonly || disabled} |
| 131 | + onChange={handleChange} |
| 132 | + defaultValue="" |
| 133 | + autoFocus={autofocus} |
| 134 | + multiple={multiple} |
| 135 | + accept={options.accept ? String(options.accept) : undefined} |
| 136 | + /> |
| 137 | + </p> |
| 138 | + <FilesInfo filesInfo={filesInfo} /> |
| 139 | + </div> |
| 140 | + ); |
159 | 141 | }
|
160 | 142 |
|
161 | 143 | export default FileWidget;
|
0 commit comments