: 사용자가 파일을 선택했을 때, 선택된 이미지를 미리보는 기능을 구현
(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) evt와 FileReader를 사용해 로직 구현
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에 있는 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; } }