<14:30 5교시>
drag & drop하는 기능을 새롭게 배울 것이다.
1. 드롭존 만들기
이 드롭존에 파일이 들어오면 dragover event가 발생하고, 마우스를 때면 drop event가 발생하게 된다.
근데 웹브라우저의 기본 드래그드롭 이벤트 처리는 새탭에서 해당 파일을 여는 것으로 실행된다.
그래서 우리는 이 디폴트 동작부터 막고 시작해야 한다.
얻어낸 files는 배열을 담고 있지만 배열로서 참조할 수는 없다. 그래서 map 함수를 쓰거나 할 수 없다.
그래서 file 안에 있는 아이템을 펼쳐놓은 실제 배열을 만든 다음 해당 배열에서 이미지 파일만 골라 놓은 새로운 배열을 만들어야 한다. 는 여러개의 이미지를 다룰려고 해서 이렇게 했엇는데 이건 나중에 gallery 만들때 하자신다.
이미지 파일만 드롭할 수 있게 해주기.
상태값 관리하기
<15:30 6교시>
이미지가 없을 때는 drag&drop 하기 전에 기본 이미지로 svg를 디코딩한 것을 띄워준다.
쌤이 보내준 코드
더보기
// src/pages/UserUpdateForm.jsx
import axios from 'axios';
import React, { useEffect, useRef, useState } from 'react';
import { Button, Form } from 'react-bootstrap';
function UserUpdateForm(props) {
const [user, setUser]=useState({});
const [imageSrc, setImageSrc]=useState(null);
useEffect(()=>{
axios.get("/user")
.then(res=>{
setUser(res.data);
//만일 등록된 프로필 이미지가 있다면
if(res.data.profileImage){
setImageSrc(`/upload/${res.data.profileImage}`);
}else{//없으면 기본 svg 이미지 출력
// person svg 이미지를 읽어들여서 data url 로 만든다음 imageSrc 에 반영하기
// svg 이미지를 2 진 데이터 문자열로 읽어들여서
const svgString=new XMLSerializer().serializeToString(personSvg.current)
// 2진데이터 문자열을 btoa (binary to ascii) 함수를 이용해서 ascii 코드로 변경
const encodedData = btoa(svgString)
// 변경된 ascii 코드를 이용해서 dataUrl 을 구성한다
const dataUrl = "data:image/svg+xml;base64," + encodedData;
setImageSrc(dataUrl);
}
})
.catch(error=>{
});
}, []);
// dropZone 의 스타일
const dropZoneStyle={
minHeight:"300px",
border:"3px solid #cecece",
borderRadius:"10px",
display:"flex",
justifyContent:"center",
alignItems:"center",
cursor:"pointer"
}
const profileStyle={
width: "200px",
height: "200px",
border: "1px solid #cecece",
borderRadius: "50%"
}
//사각형 영역에 파일이 drop 되었을때 호출되는 함수
const handleDrop = (e)=>{
e.preventDefault(); //웹브라우저의 기본 동작 막기
//drop 된 파일 객체 얻어내기
const file=e.dataTransfer.files[0];
//파일의 type을 조사해서 이미지가 아니면 함수를 종료한다.
const reg=/image/;
if(!reg.test(file.type)){
alert("이미지 파일을 drop 하세요");
return ;
}
//파일로 부터 데이터를 읽어들일 객체 생성
const reader=new FileReader()
//파일을 DataURL 형식의 문자열로 읽어들이기
reader.readAsDataURL(file)
//로딩이 완료(파일데이터를 모드 읽었을때) 되었을때 실행할 함수 등록
reader.onload=(event)=>{
//읽은 파일 데이터 얻어내기
const data=event.target.result;
//읽은 data url 을 상태값에 넣어주기
setImageSrc(data);
}
// input type="file" 요소에 drop 된 파일의 정보 넣어주기 (form 전송할때 전송이 될수 있도록)
imageInput.current.files = e.dataTransfer.files;
};
const personSvg = useRef();
const profileStyle2={
width: "200px",
height: "200px",
border: "1px solid #cecece",
borderRadius: "50%",
display: "none"
}
const imageInput = useRef();
// input type="file" 요소에 change 이벤트가 일어 났을때 호출되는 함수
const handleChange = (e)=>{
//선택한 파일 객체
const file=e.target.files[0]
//파일로 부터 데이터를 읽어들일 객체 생성
const reader=new FileReader()
//파일을 DataURL 형식의 문자열로 읽어들이기
reader.readAsDataURL(file)
//로딩이 완료(파일데이터를 모드 읽었을때) 되었을때 실행할 함수 등록
reader.onload=(event)=>{
//읽은 파일 데이터 얻어내기
const data=event.target.result
setImageSrc(data)
}
}
return (
<>
<svg ref={personSvg} style={profileStyle2} xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
<path fillRule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
</svg>
<h1>개인 정보 수정 양식</h1>
<Form>
<Form.Group className="mb-3">
<Form.Label>사용자명</Form.Label>
<Form.Control name="userName" defaultValue={user.userName} readOnly/>
</Form.Group>
<Form.Group className="mb-3" controlId="email">
<Form.Label>이메일</Form.Label>
<Form.Control name="email" defaultValue={user.email}/>
</Form.Group>
<Form.Group>
<Form.Label>프로필 이미지 ( click or drag-drop to Edit ) </Form.Label>
<Form.Control ref={imageInput} onChange={handleChange} style={{display:"none"}} type="file" name="image" accept="image/*"/>
</Form.Group>
<div className="mb-3">
<a href="about:blank" onClick={(e)=>{
e.preventDefault()
// input type="file" 요소를 강제 클릭
imageInput.current.click();
}}>
<div style={dropZoneStyle} onDragOver={(e)=>e.preventDefault()} onDrop={handleDrop}>
{ imageSrc && <img style={profileStyle} src={imageSrc} alt="프로필 이미지"/>}
</div>
</a>
</div>
<Button type="submit" variant="success" size="sm">수정확인</Button>
<Button className="ms-1" type="reset" variant="danger" size="sm">Reset</Button>
</Form>
</>
);
}
export default UserUpdateForm;
처음에 받아온 프로필 이미지 정보를 저장해놨다가 리셋 버튼을 누르면 원래의 이미지로 돌아갈 수 있게 해주기.
인풋 속성의 name과 Dto의 필드명이 같아야 한다.
와 진짜 피곤해 ㄷㄷ
<16:30 7교시>
<17:30 8교시>
에러 핸들링
react에서 사용한 비밀번호 유효성 검사도 했다.
일단 저장하고... 내일 공부해보자... 오늘은 더 못하겠다.
'자바풀스택 과정 > 자바 풀 스택 : 수업내용정리' 카테고리의 다른 글
자바 풀 스택 3/18 하루 기록 076 (0) | 2025.03.18 |
---|---|
자바 풀 스택 3/17 하루 기록 075 (0) | 2025.03.17 |
자바 풀 스택 3/14 오전 기록 074-1 (0) | 2025.03.14 |
자바 풀 스택 3/13 오후 기록 073-2 (0) | 2025.03.13 |
자바 풀 스택 3/13 오전 기록 073-1 (0) | 2025.03.13 |