在formik multistep中上传文件

问题描述 投票:0回答:3

我已经使用 formik-wizard-form 实现了 formik 多步表单。除了文件上传之外,它可以与其他输入一起正常工作。

我使用以下代码进行文件上传:

<Form.Group controlId="upload">
  <Col>
   <div className="form-group files">
     Add Attachments:
      <input 
      type="file" 
      name="upload"
      value={values.upload?.files }
      onChange={event => {
      setFieldValue("upload", event.currentTarget.files);
      }}
      multiple />
   </div>
  </Col>
</Form.Group>

控制台日志上传值如下所示。

如何将文件上传到服务器?

reactjs formik
3个回答
3
投票

文件输入的方法,如文档中所述,是:

在 React 中,

<input type="file" />
始终是不受控制的组件 因为它的值只能由用户设置,而不能以编程方式设置。

因此,它利用自己的机制以及浏览器的安全实现来设置发送文件的值。出于安全原因,您无法检索发件人本地计算机上的完整文件路径。但是,您可以使用 FileReader 对象异步读取文件内容,然后使用结果填充值并将其发送到父表单组件。

在某些情况下您可以更改文件输入的值 以编程方式,喜欢 null 来重置您的输入。

在我的多步骤表单中,我使用了formikmaterial-ui。 type="file" 的字段 (UploadField) 使用自定义 Field 组件进行包装。每当子组件因上传文件而更新时,父组件都会收到通知并开始读取指定 Blob 的内容。完成后,结果属性包含表示文件数据的数据 URL,然后将其设置为其值。目前,它接受基于使用是的为其设置的验证的图像。

传统的 application/json 类型不足以将图像上传到您的服务器;您需要使用 FormData 来代替。您需要使用表单数据编写

handleSubmit()
函数并传递由
Formik
处理的值。

您可以使用 Fetch API 或 Axios 发送 POST 请求到 您的服务器,具体取决于您的喜好。

const onSubmit = () => {
    // Create an object of formData
    const formData = new FormData();

    // Update the formData object
    formData.append("myFile", file, file.name);

    // Details of the uploaded file
    console.log(file);

    // Request made to the backend api
    // Send formData object
    axios.post("api/uploadfile", formData);
  };

// UploadForm.jsx

import React, { useState, useEffect } from "react";
import { Field, useField } from "formik";
import { Grid, FormHelperText } from "@material-ui/core";
import UploadField from "../../FormFields/UploadField";
import Thumb from "../Helper/Thumb";

const ImageForm = (props) => {
  const {
    formField: { image }
  } = props;

  const [field, meta, helper] = useField(image.name);
  const { touched, error } = meta;
  const { setValue } = helper;
  const isError = touched && error && true;
  const { value } = field;

  const [fileName, setFileName] = useState(value.name);
  const [file, setFile] = useState(value.file);
  const [src, setSrc] = useState(value.src);
  const _onChange = (e) => {
    let reader = new FileReader();
    let file = e.target.files[0];
    if (file) {
      reader.onloadend = () => setFileName(file.name);
      if (file.name !== fileName) {
        reader.readAsDataURL(file);
        setSrc(reader);
        setFile(file);
      }
    }
  };

  useEffect(() => {
    if (file && fileName && src) {
      setValue({ file: file, src: src, name: fileName });
      console.log(fileName);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [src, fileName, file]);

  return (
    <React.Fragment>
      <Grid container spacing={3} justify="center" alignItems="center">
        <Grid item xs={12}>
          <label>
            {image.label}
          </label>
          <br />
          <div
            style={{
              display: "flex",
              justifyContent: "flex-start",
              fontSize: "1.2em"
            }}
          >
            <Field
              variant="outlined"
              field={field}
              component={UploadField}
              onChange={_onChange}
              isError={isError}
            />
            {isError && <FormHelperText color={"red"}>{error}</FormHelperText>}
          </div>
        </Grid>
        <Grid item>{file && src && <Thumb file={file} src={src}></Thumb>}</Grid>
      </Grid>
    </React.Fragment>
  );
};

export default ImageForm;

//UploadField.jsx

import React from "react";
import { Field } from "formik";

const UploadField = ({
  field,
  form: { touched, errors },
  name,
  label,
  isError,
  ...props
}) => {
  return (
    <>
      <Field
        variant="outlined"
        name="uploader"
        title={label}
        type={"file"}
        {...props}
      />
    </>
  );
};

export default UploadField;

链接到代码沙箱


1
投票

Formik 不支持“开箱即用”的文件上传。因此,如果您异步上传文件,则必须执行以下操作:

const rebuildData = (values) => {
  let formData = new FormData();
  Object.keys(values).forEach(key => {
    formData.append(key, values[key]);
  });
  return formData;
};

<Formik
  onSubmit={values => {
    const data = rebuildData(values);
    axios({
        method: 'post',
        url: '/YOUR_ENDPOINT',
        data
      })
    }
  }

不要忘记将其余表单数据添加到

formData


0
投票

您可以使用 formik 中的 setFieldValue。参考:福米克

const _onChange = (e) => {
    let reader = new FileReader();
    let file = e.target.files[0];
    if (file) {
      reader.onloadend = () => setFileName(file.name);
      if (file.name !== fileName) {
        reader.readAsDataURL(file);
        setSrc(reader);
        setFieldValue('file',file);
      }
    }
  };
© www.soinside.com 2019 - 2024. All rights reserved.