【问题标题】:Can't get upload image value by using React hook form无法使用 React 挂钩表单获取上传图像值
【发布时间】:2021-09-13 12:28:46
【问题描述】:

我正在尝试构建一个可以上传多个图像的表单。
可以在预览图像期间删除图像。

例如,我上传了两张图片,然后我尝试点击删除按钮来删除两张正常工作的图片之一。

问题是在我点击提交按钮的过程中,假设会将一张图片发布到 API,但仍有两张图片发布到 API。
我正在使用 React 钩子表单,有人知道有什么问题吗? 这是项目链接 https://codesandbox.io/s/boring-hermann-xrqbt

const methods = useFormContext();
const { control, watch, setValue, formState } = methods;
const [image, setImage] = useState([]);

function deleteFile(id) {
  const s = image.filter((item, index) => item.id !== id);
  setImage(s);
}

<div className="flex justify-center sm:justify-start flex-wrap -mx-16">
  <Controller
    name="images"
    control={control}
    render={({ field: { onChange, value } }) => (
      <label
        htmlFor="button-file"
        className={clsx(
          classes.productImageUpload,
          "flex items-center justify-center relative w-128 h-128 rounded-16 mx-12 mb-24 overflow-hidden cursor-pointer shadow hover:shadow-lg"
        )}
      >
        <input
          accept="image/*"
          className="hidden"
          id="button-file"
          type="file"
          onChange={async (e) => {
            function readFileAsync() {
              return new Promise((resolve, reject) => {
                const file = e.target.files[0];
                if (!file) {
                  return;
                }
                const reader = new FileReader();

                reader.onload = () => {
                  resolve({
                    id: FuseUtils.generateGUID(),
                    url: `data:${file.type};base64,${btoa(reader.result)}`,
                    type: "image",
                  });
                };

                reader.onerror = reject;

                reader.readAsBinaryString(file);
              });
            }

            const newImage = await readFileAsync();

            setImage([newImage, ...image]);
            onChange([newImage, ...image]);
          }}
        />
        <Icon fontSize="large" color="action">
          cloud_upload
        </Icon>
      </label>
    )}
  />
  <Controller
    name="featuredImageId"
    control={control}
    defaultValue=""
    render={({ field: { onChange, value } }) =>
      image.map((media) => (
        <div
          onClick={() => onChange(media.id)}
          onKeyDown={() => onChange(media.id)}
          role="button"
          tabIndex={0}
          className={clsx(
            classes.productImageItem,
            "flex items-center justify-center relative w-128 h-128 rounded-16 mx-12 mb-24 overflow-hidden cursor-pointer outline-none shadow hover:shadow-lg",
            media.id === value && "featured"
          )}
          key={media.id}
        >
          <Icon
            className={classes.productImageFeaturedStar}
            onClick={() => deleteFile(media.id)}
          >
            Delete
          </Icon>
          <img
            className="max-w-none w-auto h-full"
            src={media.url}
            alt="product"
          />
        </div>
      ))
    }
  />
</div>;

【问题讨论】:

    标签: reactjs react-hooks react-hook-form


    【解决方案1】:


    出于安全原因,您不能以编程方式使用type="file" 设置输入的值。

    <input
      ...
      type="file"
      onChange={uploadimg}
      // remove the value prop
    />
    

    readFileAsync 函数中,您需要考虑将要出现的多个文件,因此我们将一个File 传递给它。

    您正在连接FileReader 的结果以获得有效的Base64 字符串,但您可以只使用FileReader#readAsDataURL。该函数将返回图像的Base64 字符串。

    function readFileAsync(file) {
      ...
        reader.onload = () => {
          resolve({
            id: uuid(),
            url: reader.result,
            type: "image",
          });
        };
        reader.onerror = reject;
        reader.readAsDataURL(file);
      });
    }
    

    uploadimg函数中,

    async function uploadimg(e) {
      const file = e.target.files[0];
      if (file) {
        setImage([...images, (await readFileAsync(file))]);
        setFiles([...files, file]);
      }
    }
    

    deleteFiles 函数中,现在我们必须更新imagefiles 状态。

    因为在files状态下,图像不是由任何唯一记录的,所以我们使用插入位置(from the uploadimg function)来匹配文件并删除要删除的文件。

    function deleteFile(id) {
      const imageIndex = images.findIndex(item => item.id === id);
    
      if (imageIndex > -1) {
        setImages(images.filter(item => item.id !== id));
        setFiles(files.filter((_, i) => i !== imageIndex));
      }
    }
    

    }


    为了节省

    不需要react-hook-form 包,因为不能以编程方式设置带有type="file" 值的输入。

    因此,如果是您要访问的输入中的文件

    • 您可以使用ref 访问它
    • 以另一种状态存储文件
    • 使用您生成的Base64 字符串。

    我使用另一种状态来保存CodeSandbox 中的文件,但您可以使用这三个选项中的任何一个。

    【讨论】:

    • 感谢您的解释和解决方案。但是当我单击保存按钮时仍然无法获取值
    • @sy523。检查编辑
    • 结果没有问题。但是我需要使用 react hook form 来做,因为上传是表单的一个字段,另一个字段都使用 react hook form 方法。
    • @sy523;我将使用react-hook-form 提供的setValue 函数来设置image files。然后您应该能够使用getValues 获取图像
    • @sy523;检查聊天
    猜你喜欢
    • 1970-01-01
    • 2020-10-20
    • 2021-02-06
    • 2020-06-20
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    相关资源
    最近更新 更多