英文:
How to write a custom hook for uploading files in react
问题
以下是您要的代码翻译部分:
// custom hook useFileUpload.ts
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
export const useFileUpload = initialValue => {
const [file, setFile] = useState<File | null>(initialValue);
const [error, setError] = useState(null);
const { t } = useTranslation();
useEffect(() => {
if (file) {
setError(null);
}
}, [file]);
const handleFileChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
const file = evt.target.files?.[0];
const fileName = file?.name;
const getFileExtension: string = fileName?.slice(
(Math.max(0, fileName.lastIndexOf('.')) || Infinity) + 1
) as string;
if (!file) {
return;
}
if (!/kml|gml|dxf|png|jpg/.test(getFileExtension)) {
setError(t('omgevingscheck.errors.verkeerdBestandType'));
return;
}
setFile(file);
};
return [file, error, handleFileChange];
};
// using the custom hook here
// Component with Custom Hoook
const MyComponent = () => {
const [file, error, handleFileChange] = useFileUpload(null);
const handleUploadClick = () => {
inputRef.current?.click();
};
return (
<div>
<OmgevingscheckButton
onClick={handleUploadClick}
text={t('omgevingscheck.btns.opladen')}
secondary
/>
<input
aria-label="file-upload"
className={cx(classNames)}
type="file"
onChange={handleFileChange}
ref={inputRef}
/>
{file && (
<p>
{file.name} - {file.type}
</p>
)}
{error && <p>{error}</p>}
</div>
);
}
注意:请确保您的代码中包括正确的依赖项和引入,以便上述翻译的代码能够正确运行。
英文:
I'm trying to create a custom react hook to get the value of an input.change for a file upload since I want to reuse the functionality that handles the file upload useEffect, useState , file upload, onChange..etc
in different places.
I have extracted the code to a custom hook but I'm getting the following "errors" on the UI
- I cannot see the error message..
- I cannot get the file name..
- I get 2 typescript errors (which explains error #1 and error #2 ?)
This is the actual code and the component in its original state. (prior to refactoring to a custom hook). This works as expected.
const MyComponent = () => {
const [file, setFile] = useState<File | null>(null);
const [error, setError] = useState<null>(null);
const { t } = useTranslation('app');
const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
if (file) {
setError(null);
}
}, [file]);
const handleUploadClick = () => {
inputRef.current?.click();
};
const handleFileChange = (evt: ChangeEvent<HTMLInputElement>) => {
const file = evt.target.files?.[0];
const fileName = file?.name;
const fileExtension: string = fileName?.slice(
(Math.max(0, fileName.lastIndexOf('.')) || Infinity) + 1,
) as string;
if (!file) {
return;
}
if (!/kml|gml|dxf|png|jpg/.test(fileExtension)) {
setError(t('omgevingscheck.errors.verkeerdBestandType'));
return;
}
setFile(file);
};
const classNames = {
[styles.inputIsHidden]: true,
};
return (
<div>
<OmgevingscheckButton
onClick={handleUploadClick}
text={t('omgevingscheck.btns.opladen')}
secondary
/>
<input
aria-label="file-upload"
className={cx(classNames)}
type="file"
onChange={handleFileChange}
ref={inputRef}
/>
{file && (
<p>
{file.name} - {file.type}
</p>
)}
{error && <p>{error}</p>}
</div>
);
}
When I try to refactor the hook
into a custom hook and use it I lose the functionality. I'm misunderstanding the use of a custom hook somewhere.
// custom hook useFileUpload.ts
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
export const useFileUpload = initialValue => {
const [file, setFile] = useState<File | null>(initialValue);
const [error, setError] = useState<null>(null);
const { t } = useTranslation();
useEffect(() => {
if (file) {
setError(null);
}
}, [file]);
const handleFileChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
const file = evt.target.files?.[0];
const fileName = file?.name;
const getFileExtension: string = fileName?.slice(
(Math.max(0, fileName.lastIndexOf('.')) || Infinity) + 1,
) as string;
if (!file) {
return;
}
if (!/kml|gml|dxf|png|jpg/.test(getFileExtension)) {
setError(t('omgevingscheck.errors.verkeerdBestandType'));
return;
}
setFile(file);
};
return [file, error, handleFileChange];
};
// using the custom hook here
// Component with Custom Hoook
{/*[ERROR]: Property 'type' does not exist on type 'File | ((evt: ChangeEvent<HTMLInputElement>) => void)'. Property 'type' does not exist on type '(evt: ChangeEvent<HTMLInputElement>) => void'. */}
const MyComponent = () => {
const [file, error, handleFileChange] = useFileUpload(null);
const handleUploadClick = () => {
inputRef.current?.click();
};
return (
<div>
<OmgevingscheckButton
onClick={handleUploadClick}
text={t('omgevingscheck.btns.opladen')}
secondary
/>
<input
aria-label="file-upload"
className={cx(classNames)}
type="file"
onChange={handleFileChange}
ref={inputRef}
/>
{file && (
<p>
{file.name} - {file.type}
</p>
)}
{error && <p>{error}</p>}
</div>
);
}
答案1
得分: 2
这只是一个打字错误,
TypeScript 将您的 hook 的返回类型概括为
(File | ((evt: ChangeEvent<HTMLInputElement>) => void))[]
(一个数组,其中每个项都是 File 或函数)
您可能想要显式地为您的自定义 hook 指定返回类型
export const useFileUpload = (initialValue): [File, string, ((evt: ChangeEvent<HTMLInputElement>) => void)] => { ... }
(由 File、字符串和函数组成的元组)
英文:
It is just a typing error,
Typescript is generalizing the return type of your hook as
(File | ((evt: ChangeEvent<HTMLInputElement>) => void))[]
(An array where each item is either a File or a function)
You probably want to explicity type the return type of your custom hook
export const useFileUpload = (initialValue): [File, string, ((evt: ChangeEvent<HTMLInputElement>) => void)] => {
...
}
(A tuple composed of a File, a string and a function)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论