I am quite new to React and having trouble to get the hang on how to trigger some actual events from a hook where a useEffect seems rather wrong (and leads to misbehaviour anyways).
Is there any best practice or is the use of a hook a bad idea anyways?
This is a very crude example of a file selector.
The main requirement would be that the processFile should trigger an one-time alert if the file is invalid.
import { ChangeEvent, useEffect, useState } from 'react';
export const useUploader = () => {
const [file, setFile] = useState<File | undefined>();
const [isInvalid, setIsInvalid] = useState(false);
const processFile = (inputfile: File) => {
const fileTooBig = inputfile.size > 1 * 1024 * 1024;
setFile(fileTooBig ? undefined : inputfile);
setIsInvalid(fileTooBig);
if (fileTooBig) {
// trigger event?
}
};
return { file, isInvalid, processFile };
};
export const ImageUpload = () => {
const { file, isInvalid, processFile } = useUploader();
const { t } = useTranslation();
// "Wrong appraoch" as it would also show the alert when
// translation changes or a hot-reload happens during development
useEffect(() => {
if (isInvalid) {
alert(t('Invalid file selected'));
}
}, [isInvalid, t]);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.currentTarget.files) {
processFile(e.currentTarget.files[0]);
}
};
return (
<>
<input type="file" onChange={onChange}></input>
<span>Selected file: {file?.name}</span>
<span>IsInvalid: {isInvalid ? 'Invalid' : 'All fine'}</span>
</>
);
};
You simply use a single state to represent the invalid state as well.
import { ChangeEvent, useEffect, useState } from 'react';
export const useUploader = () => {
/**
* one could use three states here
*
* undefined means the empty state
* null means an error state
* file means success state
*/
const [file, setFile] = useState<File | undefined>();
const processFile = (inputfile: File) => {
const fileTooBig = inputfile.size > 1 * 1024 * 1024;
setFile(fileTooBig ? null : inputfile);
};
const isInvalid = file === null;
return { file, isInvalid, processFile };
};
export const ImageUpload = () => {
const { file, isInvalid, processFile } = useUploader();
/**
* this is just, okay.
*/
useEffect(() => {
if (isInvalid) {
alert('Invalid file selected');
}
}, [isInvalid]);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.currentTarget.files) {
processFile(e.currentTarget.files[0]);
}
};
return (
<>
<input type="file" onChange={onChange}></input>
<span>Selected file: {file?.name}</span>
<span>IsInvalid: {isInvalid ? 'Invalid' : 'All fine'}</span>
</>
);
};