ReactJS:如何使用Formik处理图像/文件上传?

aan*_*ham 6 reducers reactjs react-redux formik

我正在使用设计网站的个人资料页面ReactJS。现在我的问题是如何从本地计算机上载图像并将其保存到数据库中并在配置文件页面中显示它

import React, {Component} from 'react';
import { connect } from 'react-redux';
import { AccountAction } from '../../actions/user/AccountPg1Action';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

class AccountInfo extends Component {
  constructor(props) {
    super(props) 
    this.state = {
      currentStep: 1,
      userAccountData: {
        userid: '',
        useravtar: '',
        attachement_id: '',
   }
  }
 }

handleFileUpload = (event) => {
  this.setState({useravtar: event.currentTarget.files[0]})
};

handleChange = event => {
    const {name, value} = event.target
    this.setState({
      [name]: value
    })    
  }

handleSubmit = event => {
    let that = this;
    const { AccountAction } = that.props;
    event.preventDefault();

    let accountInputs = {
      userid: 49,
      useravtar: that.state.image,
      attachement_id: 478,
}
    that.setState({
      userAccountData: accountInputs,
    })

    AccountAction(accountInputs)
  }
AccountInfoView = () => {
console.log(this.state.useravtar)
    return (
      <section id="account_sec" className="second_form">
      <div className="container">
      <React.Fragment>
        <Formik
          initialValues={?{
            file: null,
            email: '',
            phone: ''
          }}
          validationSchema={accountInfoSchema}
          render={(values) => {
          return(
        <Form onSubmit={this.handleSubmit}>
        <Step1 
          currentStep={this.state.currentStep} 
          handleChange={this.handleChange}
          file= {this.state.useravtar}
          handleFileUpload={this.handleFileUpload}
          />
          </Form>
        );
      }}
      />
      </React.Fragment>
      )
  }

  render() {    

    return (
      <div>{this.authView()}</div>
    )
  }
}

function Step1(props) {
console.log(props.useravtar)
  if (props.currentStep !== 1) {
    return null
  } 

  return(
    <div className="upload">
        <label htmlFor="profile">
          <div className="imgbox">
            <img src="images/trans_116X116.png" alt="" />
            <img src={props.useravtar} className="absoImg" alt="" />
          </div>
        </label>
<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
        <span className="guide_leb">Add your avatar</span>
      </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

当我handleChange为event.target.file [0] 进行控制台操作时,它的响应未定义。

此外,console.log(this.state.useravtar)handleSubmit实际操作中,它会显示路径名称,例如c:/fakepath/imgname.jpg

PS:我有多种形式,所以我Step明智地使用了它。我正在使用Redux Reducer来存储数据。

我已经引用了链接,但是我的要求看起来不是这样。

Sum*_*tty 38

Formik默认不支持文件上传,但是你可以试试下面的

<input id="file" name="file" type="file" onChange={(event) => {
  setFieldValue("file", event.currentTarget.files[0]);
}} />
Run Code Online (Sandbox Code Playgroud)

这里"file"代表您用于保存文件的密钥

在提交时,您可以通过使用获取文件的文件名、大小等

onSubmit={(values) => {
        console.log({ 
              fileName: values.file.name, 
              type: values.file.type,
              size: `${values.file.size} bytes`
            })
Run Code Online (Sandbox Code Playgroud)

如果要将文件设置为组件状态,则可以使用

onChange={(event) => {
  this.setState({"file": event.currentTarget.files[0]})};
}}
Run Code Online (Sandbox Code Playgroud)

根据您的代码,您必须按如下方式处理文件上传

在 AccountInfo 中添加一个函数来处理文件上传

handleFileUpload = (event) => {
this.setState({WAHTEVETKEYYOUNEED: event.currentTarget.files[0]})};
}
Run Code Online (Sandbox Code Playgroud)

并将相同的函数传递给 Step1 组件,如下所示

    <Step1 
      currentStep={this.state.currentStep} 
      handleChange={this.handleChange}
      file= {this.state.image}
      handleFileUpload={this.handleFileUpload}
      />
Run Code Online (Sandbox Code Playgroud)

在上传文件的 Step1 组件中,将输入更改为

<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
Run Code Online (Sandbox Code Playgroud)

如果您需要预览上传的图像,则可以创建一个 blob 并传递与图像源相同的图像,如下所示

<img src={URL.createObjectURL(FILE_OBJECT)} /> 
Run Code Online (Sandbox Code Playgroud)

编辑-1

由于URL.createObjectURL安全问题,方法已被弃用,我们需要使用srcObject媒体元素,ref例如,您可以使用它来分配 srcObject

假设您正在使用类组件,

构造函数

在构造函数中,您可以使用

constructor(props) {
  super(props)
  this.imageElRef = React.createRef(null)
}
Run Code Online (Sandbox Code Playgroud)

手柄变更功能

handleFileUpload = (event) => {
  let reader = new FileReader();
let file = event.target.files[0];
reader.onloadend = () => {
  this.setState({
    file: reader.result
  });
};
reader.readAsDataURL(file);
}
Run Code Online (Sandbox Code Playgroud)

元素

<img src={this.state.file} /> 
Run Code Online (Sandbox Code Playgroud)

  • `setFieldValue` 是从 `&lt;Formik /&gt;` 获得的,参考:https://jaredpalmer.com/formik/docs/api/formik#setfieldvalue-field-string-value-any-shouldvalidate-boolean-void (4认同)
  • 面临此错误 ==&gt; 无法设置“HTMLInputElement”的“value”属性:此输入元素接受文件名,该文件名只能以编程方式设置为空字符串。 (3认同)
  • 在哪里定义这个`setFieldValue`,它会抛出一个未定义的错误,例如:`./src/components/user/AccountInfo.jsx Line 266:'setFieldValue'未定义no-undef` (2认同)

Dia*_*aBo 13

这是我使用FormikMaterial UI解决该问题的方法

在你的 JS 文件中,只需声明一个变量 avatarPreview ,如下所示

  const [avatarPreview, setAvatarPreview] = useState('/avatars/default.png');



           <Box
            display='flex'
            textAlign='center'
            justifyContent='center'
            flexDirection='column'>
           
            <ImageAvatar size='md' src={avatarPreview || user?.avatar} />

            <Button
              variant='contained'
              component='label'
              startIcon={<CloudUploadIcon />}>
              Choose Avatar
              <input
                name='avatar'
                accept='image/*'
                id='contained-button-file'
                type='file'
                hidden
                onChange={(e) => {
                  const fileReader = new FileReader();
                  fileReader.onload = () => {
                    if (fileReader.readyState === 2) {
                      setFieldValue('avatar', fileReader.result);
                      setAvatarPreview(fileReader.result);
                    }
                  };
                  fileReader.readAsDataURL(e.target.files[0]);
                }}
              />
            </Button>
          </Box>
Run Code Online (Sandbox Code Playgroud)

默认预览: 默认头像上传

选择头像后: 选择头像后

  • 将您的头像设置为头像。哈 (6认同)