label 인데 속에 img 가 들어있는 label
두번째 label은 항상 추가되는 label
const ActivityCU = () => {
const [imgList, setImgList] = useState([]);
return (
<ImgInputWrap>
{
imgList.map((img) =>
<label>
<img
style={{
width: '100%',
height: '100%',
objectFit: 'cover',
objectPosition: 'center'
}}
src={imgList} />
<input onChange={onImgSelected} accept="image/*" type="file" />
</label>
)
}
<label>
+
<input onChange={onImgSelected} accept="image/*" type="file" />
</label>
</ImgInputWrap>
);
이제 사진을 추가하면 바로옆에 플러스가 생겨서 계속 추가 가능❗️❗️
그런데, 만약 인절미 사진을 다른걸로 바꾸려면(수정) ❓ 또는 삭제하려면 ❓
type='button'
submit
하면 새로고침되니까.
- 배열에서 클릭한애를 지워줘 라고해야한다.
{ imgList.map((img) => <label> <img style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center' }} src={imgList} /> {/* <input onChange={onImgSelected} accept="image/*" type="file" /> */} <button type='button'>삭제</button> </label> ) }
우선 ❗️우리가 올린이미지가 몇번 이미지인지 각각 구분할수있어야한다.
처음에는
imgList
는 빈 배열이였는데imgList : []
, 이미지를 클릭하면 이렇게id, previewUrl, origin
객체가 들어간다.
🌟 setImgList( [...imgList, { id, previewUrl: reader.result, originFile: e.target.files[0] } ]);
<const ActivityCU = () => {
const [imgList, setImgList] = useState([]);
const onImgSelected = (e) => {
//이미 이미지가 업로드 되었던것을 다시 선택해서 실행될때는
//기존의 배열에서 기존의 선택된 이미지를 지우고
//새로운 선택한 이미지를 배열에 추가해준다.
let now = new Date();
let id = now.toString(); // -> '2021-09-09T10:00:00'
// FileReader(); // 내가 선택한 파일을 읽어주는 객체
let reader = new FileReader(); //객체생성함
reader.readAsDataURL(e.target.files[0]); //내가 선택한 파일을 읽어주는 함수
// readAsDataURL -> 비동기함수임
//readAsDataURL()함수는 내가 선택한 파일을 읽어서 url로 만들어준다.
//이미지가 url로 만들어진 후에 실행되는 함수
reader.onload = () => { //이미지가 url로 만들어진 후에 실행되는 함수
console.log(reader.result); //이미지가 url로 만들어진다.
setImgList([...imgList, { id, previewUrl: reader.result, originFile: e.target.files[0] }]);
}
}
아이디를 날짜로 가져와서 설정할수있음(겹치지않으니까).
이렇게 원래있던것을 새로운것으로 바꾸는것.(덮어씌우기)
아니면, 있던것 삭제하고 추가해도됨 (이것의 안좋은점은, 순서가 바뀜)
근데 우리는 순서까지 그대로인것을 사용해보자❗️
기존의 배열에서 id 가 동일한 요소 찾고, 같은 id를 찾으면,
const onImgChanged = (id) => {
//이미 이미지가 업로드 되었던것을 다시 선택해서 실행될때는
//기존의 배열에서 기존의 선택된 이미지를 지우고
//🌟 기존의 배열에서 id 가 동일한 요소 찾기
//기존 imgList 라는 state변수(배열)은 변하면 안되기 때문에 똑같은 요소를 갖고있는 복제본 생성
let target = imgList.find((el) => {
return el.id === id;
})
target.previewUrl = null;
}
return(
<input
onChange={() => onImgChanged(img.id)}
accept="image/*"
type="file" />
);
선택한 요소 id 와
imgList
에 있는 id가 같은것을find()
함수로 찾아낸다.
원본을 훼손할 가능성이 있기 때문에, - state변수는 원본을 수정하면 안된다.
target.previewUrl이 바뀌면 imgurl도 같이 바뀐다. 그러면 바뀌기 전하고 후가 구분이 안된다.
let cpy = [...imgList];
//배열 복제 //새로운배열 생성. 객체가 들어있다.
여기는 문제가 생긴다.int, string 타입
이 아닌 객체가 들어있기 때문에 사용할수없음. 하지만int, string 타입
이라면 사용가능.
JSON.stringify(imgList) // 문자열로 바꿔주는 함수
JSON.parse(JSON.stringify(imgList))
cpy에 객체가 들어가있음.(원본훼손없이)
배열안에 객체가 들어가있음.
cpy의 0번째방에 ff0객체가 들어있고
cpy의 1번째방에 fb8객체가 들어있고
cpy의 2번째방에 faa객체가 들어있고
👉 복제본이 되어 서로 내용은 똑같다 (imgurl = cpy). 하지만, 완전 다른것이다.(이렇게 원본은 훼손하지않고 cpy를 수정할수있다.)
const onImgChanged = (id, e) => {
//이미 이미지가 업로드 되었던것을 다시 선택해서 실행될때는
//기존의 배열에서 기존의 선택된 이미지를 지우고
//기존의 배열에서 id 가 동일한 요소 찾기
//기존 imgList 라는 state변수(배열)은 변하면 안되기 때문에 똑같은 요소를 갖고있는 복제본 생성
// let cpy = [...imgList]; //배열 복제 //새로운배열 생성. 객체가 들어있다.
//여기는 문제가 생긴다. int, string 타입이 아닌 객체가 들어있기 때문에 사용할수없음. 하지만 int, string 타입이라면 사용가능.
let cpy = JSON.parse(JSON.stringify(imgList)); //문자열로 바꾸고 다시 객체로 바꾸면 복제본이 생성된다.
let target = cpy.find((e) => { //복제본을 넣어준다.
return e.id === id;
}); //복제본을 넣고, find 함수로 id가 같은것을 찾으면 taget이라는 이름으로 .
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]); //미리보기 url. 어떤url을 미리보기할건지()안에 넣어줘야한다. 그래서, e.target.files[0] --> 사용자가 업로드한 이미지 파일
reader.onload = () => { //다 읽어지면(완료가되면) 실행되는 함수
target.previewUrl = reader.result; //previewUrl -> 미리보기 바꾸고,
target.originFile = e.target.files[0]; //origin -> 원본파일도 바꾸고
setImgList(cpy); //setImgList에서, cpy원본으로 바꿔줘
}
}
return (
{
imgList.map((img) =>
<label style={{ position: 'relative' }} key={img.id}>
<img
style={{
width: '100%',
height: '100%',
objectFit: 'cover',
objectPosition: 'center'
}}
src={img.previewUrl} />
<input
onChange={(e) => onImgChanged(img.id, e)} //받아온 id랑 ,지금받아온 event를 받아옴
accept="image/*"
type="file" />
</label>
)
}
)
const onImgDelete = (id) => {
setImgList(imgList.filter((e) => e.id !== id));
}
return(
<button
style={{ position: 'absolute', top: '0', right: '0' }}
onClick={() => { onImgDelete(img.id) }}
type='button'>삭제하기
</button>
)