React - Image PreView / Form data 받기

김정욱·2020년 12월 9일
2

React

목록 보기
21/22
post-custom-banner

Image PreView

: 사용자가 파일을 선택했을 때, 선택된 이미지를 미리보는 기능을 구현

코드 (styled-components 제외)

(Create.js - 전체 코드)

function Create({props}) {
    const [imgSrc, setImgSrc] = useState("/images/default.gif");
    const onChangeHandle = (evt)=>{
        if(evt.target.files.length){
            var imgTarget = (evt.target.files)[0];
            var fileReader = new FileReader();
            fileReader.readAsDataURL(imgTarget);
            fileReader.onload = function(e) {
              setImgSrc(e.target.result);
            }
        }else{
            setImgSrc("/images/default.gif");
        }
    }
    const onHandleSubmit = async (evt) => {
        evt.preventDefault();
        const object = new FormData();
        object.append('img',evt.target.img.files[0]);
        object.append('userImg',evt.target.userImg.attributes.src.value);
        object.append('name',evt.target.name.value);
        object.append('subName',evt.target.subName.value);
        object.append('category',evt.target.category.value);
        object.append('term',evt.target.term.value);
        object.append('madeBy',evt.target.madeBy.value);
        object.append('active',evt.target.active.value);
        object.append('detail',evt.target.detail.value);
        try{
            console.log(object);
            const result = await postCreate(object);
            console.log(result);
            props.history.push('/');
        }catch(e){
            console.log(e);
        } 
        //console.log(object);
    }
    return (
        <Template>
            <Card>
                <Form onSubmit={onHandleSubmit}>
                    <TitleText>Post Create</TitleText>
                    <UserImg name="userImg" src="/images/userImg.png"></UserImg>
                    <ImageBox>
                        <ImgPreview src={imgSrc}/>
                        <ImgInput name="img" type='file' onChange={onChangeHandle}></ImgInput>
                    </ImageBox>
                    <NameInput name="name" type="input" placeholder="프로젝트 이름"></NameInput>
                    <SubNameInput name="subName" type="input" placeholder="구체적인 프로젝트 이름"></SubNameInput>
                    <CategoryInput name="category" type="input" placeholder="카테고리"></CategoryInput>
                    <TermInput name="term" type="input" placeholder="프로젝트 기간"></TermInput>
                    <MadeByInput name="madeBy" type="input" placeholder="작성자"></MadeByInput>
                    <ActiveInput name="active" type="input" placeholder="OB / YB"></ActiveInput>
                    <DetailInput name="detail" placeholder="내용을 입력해주세요"></DetailInput>
                    <Submit type="submit" value="등록하기"></Submit>
                </Form>
            </Card>
        </Template>
    ) 
}

export default Create

1) type이 file인 input 태그 / img태그 이렇게 두가지 태그가 필요
2) img태그의 src에 사용하는 imgSrc라는 State 생성

  /* default.img로 초기화 */
 const [imgSrc, setImgSrc] = useState("/images/default.gif");

3) input태그onChange로 이벤트 처리 함수를 지정

 <ImageBox>
     <ImgPreview src={imgSrc}/>
     <ImgInput name="img" type='file' onChange={onChangeHandle}></ImgInput>
 </ImageBox>

4) evtFileReader를 사용해 로직 구현

    const onChangeHandle = (evt)=>{
     /* length가 1이상 일 때 로직 구현 (클릭 후 취소한 경우 생각) */
        if(evt.target.files.length){
            var imgTarget = (evt.target.files)[0];
            var fileReader = new FileReader();
            fileReader.readAsDataURL(imgTarget);
            fileReader.onload = function(e) {
              /* file을 꺼내서 State로 지정 */
              setImgSrc(e.target.result);
            }
        }else{
          /* 사용자가 클릭만 하고 선택하지 않으면 default이미지 */
            setImgSrc("/images/default.gif");
        }
    }

Form Data 받기

Form에 있는 input / img의 src / file 등을 빼서 서버에 넘기기 위한 작업


1) Form에 각 요소에 name 지정 / Form에 onSubmit 지정

    <Form onSubmit={onHandleSubmit}>
        <TitleText>Post Create</TitleText>
        <UserImg name="userImg" src="/images/userImg.png"></UserImg>
        <ImageBox>
            <ImgPreview src={imgSrc}/>
            <ImgInput name="img" type='file' onChange={onChangeHandle}></ImgInput>
        </ImageBox>
        <NameInput name="name" type="input" placeholder="프로젝트 이름"></NameInput>
        <SubNameInput name="subName" type="input" placeholder="구체적인 프로젝트 이름"></SubNameInput>
        <CategoryInput name="category" type="input" placeholder="카테고리"></CategoryInput>
        <TermInput name="term" type="input" placeholder="프로젝트 기간"></TermInput>
        <MadeByInput name="madeBy" type="input" placeholder="작성자"></MadeByInput>
        <ActiveInput name="active" type="input" placeholder="OB / YB"></ActiveInput>
        <DetailInput name="detail" placeholder="내용을 입력해주세요"></DetailInput>
        <Submit type="submit" value="등록하기"></Submit>
    </Form>

2) 전체 Form을 가리키는 evt.target을 통해 요소에 접근

    const onHandleSubmit = async (evt) => {
      /* 페이지 로딩을 막아서 데이터 확인을 하기 위한 목적 */
        evt.preventDefault();

        /* multipart-form data를 보낼때에는 이렇게 해야함 */
        const object = new FormData();
        object.append('img',evt.target.img.files[0]);
        object.append('userImg',evt.target.userImg.attributes.src.value);
        object.append('name',evt.target.name.value);
        object.append('subName',evt.target.subName.value);
        object.append('category',evt.target.category.value);
        object.append('term',evt.target.term.value);
        object.append('madeBy',evt.target.madeBy.value);
        object.append('active',evt.target.active.value);
        object.append('detail',evt.target.detail.value);
        /* Form data를 확인할때는 entries를 사용! */
          for(var key of object.entries())
          {
            console.log(`${key}`);
          }  
        }
        try{
            console.log(object);
            //const result = await postCreate(object);
            //console.log(result);
            //props.history.push('/');
        }catch(e){
            console.log(e);
        } 
    }
  • file 요소 -> evt.target.img.files[0] 으로 접근
  • img의 src값 -> evt.target.userImg.attributes.src.value 로 접근
    (userImg는 정적데이터로 사용했기 때문에 정적 경로가 들어가 있음)
  • input 요소 -> evt.target.[name].value로 접근

3) 서버에 보내기 전 데이터 확인
(entries()를 사용해 내부 요소 출력)


4) multipart-form Data 전송시 axios에서 적용할 것!
: url , data , option 3개의 매개변수를 사용해 Content-Type지정!

const postCreate = async (object) => { 
    try {
        const { data } = await axios.post(`${url}/projects/read`, object, {
            headers: {
              'Content-Type': 'multipart/form-data'
            }
        });
        return data.data;
    } catch (e) {
        console.error('[FAIL] POST ANSWER', e);
        return e;
    }
}
profile
Developer & PhotoGrapher
post-custom-banner

0개의 댓글