英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论