Integration with react-dropzone #2146
-
I need help integrating import React from 'react'
import {useForm} from 'react-hook-form'
import {DevTool} from '@hookform/devtools'
import {useDropzone} from 'react-dropzone'
export default function Form() {
const {handleSubmit, register, control} = useForm()
const {getRootProps, getInputProps} = useDropzone()
function onSubmit(data) {
console.log(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div {...getRootProps()}>
<input
ref={register({required: true})}
{...getInputProps({name: 'base64'})}
/>
<p>- Drag 'n' Drop file here -</p>
</div>
<DevTool control={control} />
</form>
)
} Thank you for any suggestions and great job with this library 😁 |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 28 replies
-
try with Controller with |
Beta Was this translation helpful? Give feedback.
-
Hi Bill, I tried the solution on this discussion but this only works with the click and search option. |
Beta Was this translation helpful? Give feedback.
-
Here is TypeScript example using the import { useForm, SubmitHandler, Controller } from 'react-hook-form';
import Dropzone from 'react-dropzone';
type FormInputs = {
file: FileList;
};
export default function App() {
const form = useForm<FormInputs>();
const onSubmit: SubmitHandler<FormInputs> = (data) => {
console.log(data);
};
return (
<div>
<form onSubmit={form.handleSubmit(onSubmit)}>
<Controller
control={form.control}
name="file"
rules={{
required: { value: true, message: 'This field is required' },
}}
render={({ field: { onChange, onBlur }, fieldState }) => (
<Dropzone
noClick
onDrop={(acceptedFiles) => {
form.setValue('file', acceptedFiles as unknown as FileList, {
shouldValidate: true,
});
}}
>
{({
getRootProps,
getInputProps,
open,
isDragActive,
acceptedFiles,
}) => (
<div>
<div
style={{
borderStyle: 'dashed',
backgroundColor: isDragActive ? `#808080` : 'transparent',
}}
{...getRootProps()}
>
<input
{...getInputProps({
id: 'spreadsheet',
onChange,
onBlur,
})}
/>
<p>
<button type="button" onClick={open}>
Choose a file
</button>{' '}
or drag and drop
</p>
{acceptedFiles.length
? acceptedFiles[0].name
: 'No file selected.'}
<div>
{fieldState.error && (
<span role="alert">{fieldState.error.message}</span>
)}
</div>
</div>
</div>
)}
</Dropzone>
)}
/>
<button>Submit</button>
</form>
</div>
);
} |
Beta Was this translation helpful? Give feedback.
-
I notice that these working samples are relied on |
Beta Was this translation helpful? Give feedback.
-
I was experiencing some related unexpected behaviour. The Instead pass an This works: function Form() {
const { register, handleSubmit, setValue } = useForm({});
const dropzone = useDropzone({
onDrop: ([file]) => file && setValue("file", file),
});
return (
<form onSubmit={handleSubmit(console.log)}>
<div {...dropzone.getRootProps()}>
Drop here
<input
{...dropzone.getInputProps({
...register("file"),
})}
/>
</div>
<button type="submit">Upload</button>
</form>
);
}; This doesn't: function Form() {
const { register, control, handleSubmit, setValue } = useForm({});
const dropzone = useDropzone();
return (
<form onSubmit={handleSubmit(console.log)}>
<Controller
control={control}
name="file"
render={({ field: { onBlur } }) => {
return (
<div {...dropzone.getRootProps()}>
Drop here
<input
{...dropzone.getInputProps({
onChange: (e) => setValue(e.target.files),
onBlur,
})}
/>
</div>
);
}}
/>
<button type="submit">Upload</button>
</form>
);
} |
Beta Was this translation helpful? Give feedback.
-
I found a really great solution that uses |
Beta Was this translation helpful? Give feedback.
-
With Mui and React Hook Form, this can work, adapt it only to your needs, I omitted some code that I can't publish, I hope it helps someone. import {
Controller,
FieldValues,
FieldPath,
UseFormReturn,
RegisterOptions,
FieldErrors,
FieldName,
} from 'react-hook-form'
import {
ErrorMessage,
FieldValuesFromFieldErrors,
} from '@hookform/error-message'
import {
Box,
Button,
Card,
CardContent,
Grid,
LinearProgress,
ListItem,
ListItemIcon,
ListItemText,
Stack,
Typography,
useTheme,
} from '@mui/material'
import Dropzone, { DropzoneProps } from 'react-dropzone'
import FileUploadIcon from '@mui/icons-material/FileUpload'
import DescriptionIcon from '@mui/icons-material/Description'
import { useCallback, useState } from 'react'
interface Props<TFieldValues extends FieldValues>
extends Omit<DropzoneProps, 'onDrop'> {
name: FieldPath<TFieldValues>
control: UseFormReturn<TFieldValues>['control']
rules?: RegisterOptions
onChange?: (value: string | null) => void
errors: FieldErrors<TFieldValues>
}
const FormDrag = <TFieldValues extends FieldValues>({
name,
control,
rules,
onChange,
errors,
...rest
}: Props<TFieldValues>) => {
const theme = useTheme()
const [file, setFile] = useState<File | null>(null)
const [isUploading, setIsUploading] = useState(false)
const [finished, setFinished] = useState(false)
const onReset = () => {
setIsUploading(false)
setFinished(false)
setFile(null)
}
const onDropHandler = useCallback(
(acceptedFiles: File[], onControllerChange: (value: string) => void) => {
const uploadFile = Array.isArray(acceptedFiles)
? acceptedFiles[0]
: acceptedFiles
if (uploadFile) {
setFinished(false)
setFile(uploadFile)
setIsUploading(true)
fetchSomething({....})
.unwrap()
.then(({ .......}) => {
otherPrivateFetch({ ...... })
.unwrap()
.then(() => {
onControllerChange("whateveryouneed")
onChange && onChange("whateveryouneed")
setIsUploading(false)
setFinished(true)
})
.catch(() => onReset())
})
.catch(() => onReset())
}
},
[]
)
return (
<Controller
name={name}
control={control}
rules={rules}
render={({ field: { onChange: onControllerChange, onBlur } }) => (
<Grid item container>
{!isUploading && file === null && (
<Dropzone
onDrop={(acceptedFiles) => {
onDropHandler(acceptedFiles, onControllerChange)
}}
{...rest}
>
{({ getRootProps, getInputProps, open, isDragActive }) => {
return (
<Card
variant="outlined"
component="div"
elevation={0}
sx={{
px: 4,
width: '294px',
height: '195px',
backgroundColor: theme.palette.gray.main,
}}
{...getRootProps()}
>
<CardContent>
<Box
component="input"
{...getInputProps({
onBlur,
})}
/>
<Grid
item
container
direction="column"
justifyContent="center"
alignItems="strech"
rowGap={2}
wrap="nowrap"
>
<Grid item xs={12}>
<Stack
direction="column"
width="100%"
justifyContent="center"
alignItems="center"
gap={1}
>
<FileUploadIcon color="darkGrey" />
<Typography
variant="body1"
component="p"
textTransform={
!isDragActive ? 'capitalize' : 'uppercase'
}
textAlign="center"
color={theme.palette.darkGrey.main}
>
{!isDragActive
? 'firstText'
: 'Dragtext'}
</Typography>
{.......morecomponents}
</Stack>
</Grid>
<Grid
item
container
justifyContent="center"
alignItems="strech"
xs={12}
sx={{
display: !isDragActive ? 'block' : 'none',
}}
>
<Button
fullWidth
type="button"
onClick={open}
variant="outlined"
sx={{
py: 1,
px: 2,
color: 'common.black',
border: `3px solid ${theme.palette.primary.main}`,
borderRadius: '15px',
'&:hover': {
borderWidth: '3px',
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
},
}}
>
{..........button_text}
</Button>
</Grid>
</Grid>
</CardContent>
</Card>
)
}}
</Dropzone>
)}
{!!file && (
<Grid
item
container
xs={12}
direction="row"
justifyContent="flex-start"
alignItems="center"
sx={{ pl: 2 }}
>
<Grid item xs={12}>
<ListItem disablePadding disableGutters>
<ListItemIcon sx={{ minWidth: 0, mr: 2 }}>
<DescriptionIcon />
</ListItemIcon>
<ListItemText
primary={file.name}
primaryTypographyProps={{
variant: 'subtitle1',
fontWeight: 600,
}}
/>
</ListItem>
<LinearProgress
sx={{
marginTop: 0.5,
maxWidth: '294px',
}}
variant="determinate"
value={finished && !isUploading ? 100 : 0}
/>
</Grid>
</Grid>
)}
{errors && (
<Grid item xs={12} sx={{ mt: 1 }}>
<ErrorMessage
errors={errors}
name={
name as unknown as FieldName<
FieldValuesFromFieldErrors<FieldErrors<TFieldValues>>
>
}
render={({ message }) => {
return (
<Typography
variant="body2"
component="p"
color={theme.palette.error.main}
>
{message}
</Typography>
)
}}
/>
</Grid>
)}
</Grid>
)}
/>
)
}
export default FormDrag in Client code you can use like this <FormDrag
name="passwordKey"
control={control}
errors={errors}
documentId={3}
noClick
noKeyboard
maxFiles={1}/> |
Beta Was this translation helpful? Give feedback.
try with Controller with
render
prop, all you need is to wire up theonChange
andvalue
of the component.