programing

React JS:Formik을 사용하여 이미지/파일 업로드를 처리하는 방법

css3 2023. 3. 16. 21:41

React JS: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>
  )
}

에서 콘솔을 실행할 때handleChangeevent.target 액션.file [ 0 ]는 정의되지 않은 상태로 응답합니다.

또, 을 하는 것console.log(this.state.useravtar)handleSubmit다음과 같은 경로 이름을 표시합니다.c:/fakepath/imgname.jpg

추신: 여러 개의 양식이 있기 때문에Step그리고 데이터를 저장하기 위해 Redux Reducer를 사용하고 있습니다.

저는 이 링크를 참조했지만, 제 요구 사항은 이렇지 않습니다.

Formik은 기본적으로 파일 업로드를 지원하지 않지만 다음을 시도할 수 있습니다.

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

여기서"file"파일 보관에 사용하는 키를 나타냅니다.

송신시에, 다음의 방법으로 파일의 파일명, 사이즈등을 취득할 수 있습니다.

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

파일을 컴포넌트 상태로 설정하려면

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

당신의 코드에 따라 당신은 아래와 같이 파일 업로드를 처리해야 합니다.

AccountInfo에서 파일 업로드를 처리하는 기능을 추가합니다.

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

그리고 스텝1 컴포넌트에 다음과 같이 같은 기능을 전달합니다.

    <Step1 
      currentStep={this.state.currentStep} 
      handleChange={this.handleChange}
      file= {this.state.image}
      handleFileUpload={this.handleFileUpload}
      />

1단계 파일을 업로드하는 컴포넌트에서 입력 내용을 다음과 같이 변경합니다.

<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>

업로드한 이미지를 미리 볼 필요가 있는 경우는, 아래와 같이 BLOB를 작성해, 이미지의 소스와 같은 것을 전달할 수 있습니다.

<img src={URL.createObjectURL(FILE_OBJECT)} /> 

편집-1

~하듯이URL.createObjectURL보안 문제로 인해 권장되지 않는 메서드입니다.srcObjectMedia Elements에서 사용할 수 있는 것을 사용하려면ref예를 들어 srcObject를 할당합니다.

클래스 컴포넌트를 사용하고 있다고 가정하면,

컨스트럭터

컨스트럭터에서는

constructor(props) {
  super(props)
  this.imageElRef = React.createRef(null)
}

핸들 교환 기능

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

요소

<img src={this.state.file} /> 

Formik과 Material UI로 해결한 방법은 다음과 같습니다.

JS 파일에서 다음과 같은 변수 아바타 Preview를 선언합니다.

  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>

기본 미리 보기:

아바타를 선택한 후:

다음과 같이 Formik을 사용하여 유효성 검사를 통해 단일 또는 여러 파일을 업로드할 수 있습니다.

import "./App.css";
import { useEffect, useState } from "react";
import * as Yup from "yup";
import { Formik, Field, Form, ErrorMessage, useField } from "formik";
import axios from "axios";


function App() {
  return (
    <Formik
      initialValues={{
        profile: [],
      }}
      validationSchema={Yup.object({
        profile:Yup.array().min(1,"select at least 1 file")
      })}
      onSubmit={(values, props) => {
        let data = new FormData();
        values.profile.forEach((photo, index) => {
          data.append(`photo${index}`, values.profile[index]);
        });
        axios
          .post("you_api_for_file_upload", data, {
            headers: {
              "Content-Type": "multipart/form-data",
            },
          })
          .then((response) => {
            console.log(response);
          })
          .catch((err) => {
            console.log(err);
          });
      }}
    >
      {(formik) => {
        return (
          <>
            <Form>
              <input
                id="file"
                name="profile"
                type="file"
                onChange={(event) => {
                  const files = event.target.files;
                  let myFiles =Array.from(files);
                  formik.setFieldValue("profile", myFiles);
                }}
                multiple
              />
              <ErrorMessage name="profile"/>
              <button type="submit" disabled={formik.isSubmitting}>
                Submit
              </button>
            </Form>
          </>
        );
      }}
    </Formik>
  );
}

export default App;

참고: 필요에 따라 최소값(선택 사항, "메시지")사용자 정의할 수 있습니다.

   validationSchema={Yup.object({
        profile:Yup.array().min(1,"select at least 1 file")
      })}

백엔드로 포맷된 파일을 처리하려면 아래 입력만 추가하면 됩니다(아바타를 원하는 형식으로 변경할 수 있습니다).

<input
 type="file"
 name="avatar"
 onChange={(event) => {
 setFieldValue('avatar', event.currentTarget.files[0]);
 }}
 />

onSubmit는 값 obj like values.avatar를 사용하여 파일에 액세스할 수 있습니다.

서버측(Express)에서 파일에 액세스하려면 req.file을 사용합니다.서버측에서 처리하려면 파일을 자동으로 검출하는 multer도 사용해야 합니다.

FormIk는 파일 업로드를 지원하지 않기 때문에 커스텀 방식으로 해야 합니다.onChange 이벤트를 트리거하고 파일을 설정합니다.

TypeScript에서 setFieldValue 오류가 발생한 경우 다음과 같이 하십시오.

onChange={(event) => {
   if (event.currentTarget.files) {
       formik.setFieldValue(
           "file",
            event.currentTarget.files[0]
        );
   }

백엔드로 포맷된 파일을 처리하려면 아래 입력만 추가하면 됩니다(아바타를 원하는 형식으로 변경할 수 있습니다).

<input
 type="file"
 name="avatar"
 onChange={(event) => {
 setFieldValue('avatar', event.currentTarget.files[0]);
 }}
 />

onSubmit는 값 obj like values.avatar를 사용하여 파일에 액세스할 수 있습니다.

서버측(Express)에서 파일에 액세스하려면 req.file을 사용합니다.서버측에서 처리하려면 파일을 검출하는 multer 및 cloudinary도 사용해야 합니다.

나는 간단한 속임수를 썼다.

<Field name="image">
{ (form , meta , value ) =>
const {setFieldValue} = form 
return (  
<input name="image" type="file" onChange={(e) => setFieldValue(e.target.file[0])}
)
}
</Field>

for multiple image
<input name="image" type="file" onChange={(e) => setFieldValue(e.target.files)}
or use loop
for( i=0 ; i < e.target.file; i++){
setFieldValue([...image , e.target.file])
}

언급URL : https://stackoverflow.com/questions/56149756/reactjs-how-to-handle-image-file-upload-with-formik