react에서 이미지 업로드, 미리보기, 삭제하기를 제작하려고 한다.
(function방식으로 제작 react hook을 활용하여 제작한다.)
새롭게 추가할 사진 배열 설정
const [imageItems, setImageItems] = React.useState([]);
useState를 이용해 imageItems라는 배열을 설정한다
배열에 첨부될 object는
{ id: 파일이름, file: 사진파일, url: 사진파일 url }
형식이 될것이다
사진을 불러들일수있는 input 태그를 설정한다
<input
type={'file'}
accept={'image/*'}
ref={photoInput}
onChange={handleAddImageFile}
style={{ display: 'none' }}
/>
위 input 에서 체크 해야할 사항은
따로 버튼을 두어 useRef를 활용하여 ref로 클릭을 연결해주기 위함이다.
handleAddImageFile 함수를 만들어보자
const handleAddImageFile = (e) => {
e.preventDefault()
let reader = new FileReader()
let file = e.target.files ? e.target.files[0] : null
if (!file) {
return
}
reader.onloadend = () => {
setImageItems([
...imageItems,
{ id: file.name, file: file, imagePreviewUrl: reader.result },
])
}
reader.readAsDataURL(file)
}
handleAddImageFile 는 이미지를 load하고 파일불러오기에서 파일을 선택시 imageItems에 넣어주는 역활을 한다.
useRef를 활용하여 photoInput를 등록해주고 input내부의 ref에 담아준다
const photoInput = useRef()
const handleAddPhotoClick = () => {
photoInput.current.click()
}
이후 버튼에 onClick 이벤트로 handleAddPhotoClick를 넣어주면 된다
useRef를 활용한 current.click()함수로 인해 버튼에 input기능을 실행할수있게 가능하다
<button
onClick={() => handleAddPhotoClick()}
>
<closeIcon/>
이미지 추가하기
</button>
이제 추가된 배열을 매핑한다.
<div direction="row">
{imageItems.map((item, index) => {
return (
<ImageBox
key={index}
// absolute 대상 선택을위해 relative 설정
style={{ position: 'relative' }}
//클릭시 삭제 처리
onClick={() => contentRemoveImage(item.imagePreviewUrl)}
>
<img src={item.imagePreviewUrl} />
<div className="bg_hover" /> //마우스 hover시 삭제style 제작
<div className="bg_hover_text">삭제</div> //마우스 hover시 삭제style 제작
</ImageBox>
)
})}
</div>
map 을 이용해 배열 imageItems을 활용해 item 내부의 인자값들을 활용해서 image요소들에 각요소들에 넣어준다
매핑후 필자는 style-component를 사용하여 내용을 지정하여 style처리를 해주었다.
매핑 스타일은 아래와 같다
const ImageBox = styled.div`
width: 60px;
height: 60px;
overflow: hidden;
background-color: rgba(150, 150, 180, 0.3);
margin: 2px;
border-radius: 4px;
cursor: pointer;
box-sizing: border-box;
& .bg_hover {
background-color: rgba(0, 0, 0, 0.48);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: ease-in-out 0.2s;
opacity: 0;
border: 3px solid rgb(100, 100, 100);
}
& > div.bg_hover_text {
opacity: 0;
color: #fff;
padding: 8px;
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, -50%);
transition: ease-in-out 0.2s;
}
&:hover .bg_hover,
&:hover div.bg_hover_text {
opacity: 1;
}
& > img {
width: 100%;
height: 100%;
object-fit: cover;
transition: ease-in-out 0.25s;
}
&:hover > img {
transform: scale(1.15);
opacity: 0.8;
}
`
const contentRemoveImage = (deleteUrl: any) => {
setImageItems(imageItems.filter(item => item.imagePreviewUrl !== deleteUrl))
}
contentRemoveImage함수를 만들어 준다
배열 imageItems 내부를 탐색 filter()를 이용해 선택한 대상과 같지 않은 url을 남겨준다.
contentRemoveImage 함수는 삭제하길 원하는 대상의 위치에 onClick이벤트로 넣어주면 된다
{imageItems.map((item, index) => {
return (
<ImageBox
key={index}
// absolute 대상 선택을위해 relative 설정
style={{ position: 'relative' }}
//클릭시 삭제 처리
onClick={() => contentRemoveImage(item.imagePreviewUrl)}
>
<img src={item.imagePreviewUrl} />
<div className="bg_hover" /> //마우스 hover시 삭제style 제작
<div className="bg_hover_text">삭제</div> //마우스 hover시 삭제style 제작
</ImageBox>
)
})}
이렇게 하면 contentRemoveImage 내부의 인자값으로 받아온 item.imagePreviewUrl을 활용하여 대상을 제거 할수있다
handleAddImageFile함수 내부에서 업로드하는 file에 접근이 가능하기 때문에
이를 활용하여
if (file.size > 3024) {
alert('파일 사이즈가 너무 큽니다.')
return
}
등 file크기제한, 이미지크기조절등 다양하게 활용할수 있다.
이미지 파일을 배열 imageItems에 모아놓은 상태이기에 이를 활용하여 업로드, 전송등 이 가능하다