Soy bastante nuevo en React y tengo problemas para entender cómo desencadenar algunos eventos reales desde un gancho donde un useEffect parece bastante incorrecto (y conduce a un mal comportamiento de todos modos).
¿Hay alguna mejor práctica o el uso de un gancho es una mala idea de todos modos?
Este es un ejemplo muy crudo de un selector de archivos. El requisito principal sería que el processFile de proceso debería activar una alerta única si el archivo no es válido.
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> </> ); };Simplemente usa un solo estado para representar también el estado inválido.
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> </> ); };