- 기존 이미지 업로드 방식은 비효율적이야! → FileReader
- Async-await를 for문에서 쓰면 안된다고? → Promise.all
- 이미지를 내가 원할 때 불러올 수 있대! → LazyLoad, PreLoad
이미지에 관한 것들을 배웠다!
이미지 업로드 최적화하기! 그리고 모아서 보낼 때 어떻게 기다리는지! 그리고 이미지를 불러오는 페이지에서 어떻게 이미지를 가져오는지!
이미지 업로드 _ 업로드 최적화
1. 이미지 업로드 해놓고 게시글 등록 안 하고 뒤로가기를 눌렀다, 그럼 스토리지엔 파일 저장되어있지? 이게 쌓이고 쌓여! 찌꺼기... 회사 입장에선 손해!
2. 파일 올리고 다운로드 URL 받아와서 그걸 보여주는거라 이미지 미리보기가 늦게 뜬다. 미리보기는 빨리 볼 수 없어?!
그래서 새로운 방법.
- 이미지 파일 업로드하면 백엔드로 안가고 브라우저에서도 바로 볼 수 있는 url주소로 변형해서 바로 미리보기 보여준다. → 미리보기 속도 빨라짐
- 파일은 state같은 곳에 넣어뒀다가, 등록하기 버튼을 클릭했을 때 createBoardAPI 바로 나가는 게 아니라 두 개 API 동시에 요청(uploadFile로 url을 받고 → 그걸 첨부해서 createBoard) → 파일 찌꺼기 남지 않는다.


스토리지에 저장된 이미지주소 다운로드 된 주소기 때문에 이미지 문자 자체는 용량이 얼마 안된다.
원본은 스토리지에 저장되어있는 것.
파일을 가지고 변경한 주소는 이 주소 자체가 원본. 그래서 이 자체가 이미지 사이즈+a
둘 다 이미지 태그로 보여줄 수 있지만, 스토리지에 저장된 이미지주소가 용량면에선 훨씬 더 효율적이다.
내 컴퓨터에서만 볼 수 있는 임시 미리보기 주소도 만들 수 있다.
const result = URL.createObjectURL(file);
console.log(result); // 미리보기 주소가 만들어진다. 내 컴퓨터에서만 볼 수 있는 가짜주소! 미리보기 용으론 괜찮을 수도?
// 파일리더가 옛날부터 있던 기능이고, 이건 최근에 나온 기능이어서 지원이 안되는 브라우저들도 있다.
ㄴ 이건 가짜 주소라서 금지, 파일을 가지고 변경한 주소는 진짜인데 용량 때문에 백엔드 전송 금지!
event?.target.files[0]; (파일이 없으면 어떡할건데)
event?.target.files?.[0]; (?. 를 붙여준다)
Promise-all _ 이미지 여러개 보내기
await는 promise 앞에만 달 수 있는 것!
mutation, axios ... 마우스 올려보면 반환타입이 promise!

promise는 resolve를 만나야 종료된다.
resolve 끝날 때까진 대기 상태, 그 밑으론 내려갈 수 없어!
그리고 promise가 없어지는 순간 밑으로 내려가서 console.log들을 수행할 수 있게 된다.
Promise.all - promise들의 배열, 동시에 실행하고 기다리자~
const result = await Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("https://dog1.jpg");
}, 3000);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("https://dog2.jpg");
}, 2000);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("https://dog3.jpg");
}, 1000);
}),
]); // promise들의 배열, 세 개 동시에 실행하고 세 개 동시에 기다리는거야!!그래서 각각에는 await를 붙이지 않는다.
console.log(result); // 결과값도 배열로 들어온다.
→ 최대시간인 3초 안에 모든 게 끝난다!
const tempUrls = [...imageUrls]
tempUrls[number] = data.target?.result
setImageUrls(tempUrls);
const tempFiles = [...files];
tempFiles[number] = file;
setFiles(tempFiles);
// 얕은 복사 - imageUrls[number] = data.target.results, 원본 자체를 바꿔서 바껴도 리렌더 안됨.
새로운 배열에서 수정하고 그 배열을 다시 반영시켜줘야한다. 그래야 리렌더가 됨
사실 여기 잘 이해안됐다... 얕은 복사는 주소를 복사하는 것이기 때문에 복사한 것의 값을 바꾸면 원본의 값까지 바뀌게 된다. 근데 원본 값까지 바껴서 리렌더가 안되는건 뭐지? 그리고 왜 리렌더가 되게 만들어야 하는거지??
이미지에 대해서만 하는 게 아니라, 여러개 작업하는데 await로 기다려야 하는 작업이 있을 때, 그걸 어떻게 기다릴지에 대해 생각해보기. 31-03-promise-all 과 같이 연결해서 보면 좋다!
오늘 수업은 map쓰는 법에 대해 더 잘 알게 된 수업~~~진짜 map은 안 쓸 수가 없구나... 걍 냅다 써봐도 되는 것 같을 정도로 많이 쓴다.
Lazyload, Preload
Lazyload
눈에 보이는 화면, 그 밑에 더 있어. 아래쪽에 나올 이미지도 미리 다운 받아놔야하나? 그럼 속도만 느려지지.
그렇게하지말고 일단 보이는 부분만 다운로드 받아서 보여주자. 스크롤 내릴때 추가로 다운받아 보여주자.
(ex. 크몽 홈페이지에 들어가서 네트워크 탭을 보면 스크롤 내릴 때마다 이미지가 추가되는 걸 볼 수 있다.)
https://yarnpkg.com/package/react-lazyload
yarn add react-lazyload
Preload
너무 큰 사이즈의 이미지를 보여준다고 할 때, 조금씩 조금씩 더 보여주는데… 미리 다운로드 해놓고 들어가면 짠 보여주게 하면 UX에 좋겠지!
이탈율과 관련이 있다.
네트워크 노 쓰로틀링 - fast3G 누르면 아주 구진 2012년도의 폰으로 돌아간듯한 느낌을 받을 수 있다.
새로고침하면 굉장히 느려요… 하지만 이미지 로딩이 일어나진 않았다. (두둥,,, 귀엽)
import { useEffect, useState, useRef } from "react";
export default function ImagePreloadPage() {
const [isLoaded, setIsLoaded] = useState(false);
const [imgTag, setImgTag] = useState<HTMLImageElement>();
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const img = new Image(); // 그냥 이미지 태그
img.src =
"https://upload.wikimedia.org/wikipedia/commons/9/96/%22Den_kjekke_gutt%22_-_6._Internasjonale_Akademiske_Vinterleker_%281939%29_%2840200856483%29.jpg";
img.onload = () => {
setImgTag(img);
};
}, []);
const onClickLoad = () => {
setIsLoaded(true);
};
const onClickPreload = () => {
// document.getElementById("id")?.appendChild(imgTag);
if (imgTag) divRef.current?.appendChild(imgTag);
};
return (
<div>
<div ref={divRef}></div>
<button onClick={onClickPreload}>이미지 프리로드</button>
===========*===========
{isLoaded && (
<img src="https://4.bp.blogspot.com/-vDZeDAjI2tg/WMg8JBT3aEI/AAAAAAAAD7E/bErlr_iSj5w0Jp2W0nj9W82sDmUZIkJjwCLcB/s1600/test1_0000.gif" />
)}
<button onClick={onClickLoad}>이미지 일반로드</button>
</div>
);
}
그냥 useEffect에서 파일을 전부 다운로드 받으면 된다!
lazyload
https://yarnpkg.com/package/react-lazyload
yarn add react-lazyload
page-speed-insights 사이트
https://pagespeed.web.dev/
이미지 관련 라이브러리
react-dropzone
https://yarnpkg.com/package/react-dropzone
react-avatar-editor
이미지 사이즈, 형태 변형 시키고 싶을 때 쓰는 라이브러리
react-beautiful-dnd
카드 형태들을 드래그앤드롭 해서 옮길 수 있는 기능
팀 포트폴리오 작업할 때 적용해보면 좋을 것 같다!
(실제로 전기수에서 드래그앤드롭 방식을 적용한 프로젝트를 하셨었음)
이런건 라이브러리 사용법을 익히는 것이 중요함
어떤 회사를 가든 쓰고 있을 수 있기 때문에…
마음가짐 자체가 변해야해… 회사 비용 줄일 수 있는 개발자 ^^b
주니어가 하기엔 좀 어렵다.
Lazyload
yarn add react-lazyload
import LazyLoad, { lazyload } from "react-lazyload";
export default function LazyLoadPage() {
return (
<div>
<LazyLoad height={200}>
<img src="/img/kirby-happy.gif" />
</LazyLoad>
{/* <LazyLoad height={200} once>
<img src="/img/kirby-happy.gif" />
</LazyLoad> */}
<LazyLoad height={200} offset={100}>
<img src="/img/kirby-happy.gif" />
</LazyLoad>
<LazyLoad>
<img src="/img/food-coma-food.gif" />
</LazyLoad>
<LazyLoad height={200}>
<img src="/img/베아트리스.jpg" />
</LazyLoad>
<LazyLoad height={200}>
<img src="/img/베아트리스콘서트.png" />
</LazyLoad>
<LazyLoad height={200}>
<img src="/img/아만.png" />
</LazyLoad>
</div>
);
}
lazyload가 되긴하는데, 속성들이 뭔뜻인지...^^
도와줘 파파고~~!!
첫 번째 렌더링 라운드에서 LazyLoad는 플레이스홀더가 제공되지 않을 경우 구성 요소의 플레이스홀더를 렌더링하고 이 구성 요소가 표시되는지 여부를 측정합니다. 높이를 올바르게 설정하면 LazyLoad가 더 정확하게 계산됩니다. 값은 '100%'와 같은 숫자 또는 문자열일 수 있습니다. 높이를 사용하는 대신 css를 사용하여 자리 표시자의 높이를 설정할 수도 있습니다.
???

As the user scrolls down the page, the image placeholders start coming into viewport (visible part of the webpage). We trigger the load for these images when they become visible.
(출처 : https://imagekit.io/blog/lazy-loading-images-complete-guide/)
스크롤하면 이미지 플레이스홀더가 뷰포트(웹페이지에서 눈에 보이는 곳)로 들어오기 시작하고, 그때 이미지가 로드되게 한다.
정확히는 모르겠다... 아!!!!!!! ~~~~ 검색하다 찾았다.
실제 이미지가 아니라 그냥 흰색 박스 같은 것, 정말 이미지가 들어오기 전에 그 자리를 대신하고 있는 이미지를 뜻한다!
height는 placeholder의 높이를 뜻한다. ~~~
scrollContainer
Type: String/DOM node Default: undefined
Pass a query selector string or DOM node. LazyLoad will attach to the window object's scroll events if no container is passed.
height
Type: Number/String Default: undefined
In the first round of render, LazyLoad will render a placeholder for your component if no placeholder is provided and measure if this component is visible. Set height properly will make LazyLoad calculate more precisely. The value can be number or string like '100%'. You can also use css to set the height of the placeholder instead of using height.
once
Type: Bool Default: false
Once the lazy loaded component is loaded, do not detect scroll/resize event anymore. Useful for images or simple components.
offset
Type: Number/Array(Number) Default: 0
Say if you want to preload a component even if it's 100px below the viewport (user have to scroll 100px more to see this component), you can set offset props to 100. On the other hand, if you want to delay loading a component even if it's top edge has already appeared at viewport, set offset to negative number.
Library supports horizontal lazy load out of the box. So when you provide this prop with number like 100 it will automatically set left edge offset to 100 and top edge to 100;
If you provide this prop with array like [100, 200], it will set left edge offset to 100 and top offset to 200.
scroll
Type: Bool Default: true
Listen and react to scroll event.
resize
Type: Bool Default: false
Respond to resize event, set it to true if you do need LazyLoad listen resize event.
NOTICE If you tend to support legacy IE, set this props carefully, refer to this question for further reading.
overflow
Type: Bool Default: false
If lazy loading components inside a overflow container, set this to true. Also make sure a position property other than static has been set to your overflow container.
placeholder
Type: Any Default: undefined
Specify a placeholder for your lazy loaded component.
If you provide your own placeholder, do remember add appropriate height or minHeight to your placeholder element for better lazyload performance.
출처 : https://yarnpkg.com/package/react-lazyload
문제해결

갓커피빈 멘토님,,,, ,,,, 사실상 그냥 턱 보여주면서 문제 찾아줘요~! 한거나 다름없는데 바로 찾아주셨다 으아악, ,, ,
이건 수정한 코드고, 원래는 export default function - 밑에 const ToastEditor ~ 가 있었다.
그래서 state가 바뀔때마다 다시 토스트 에디터를 임포트 해와서 계속 초기화 됐던 거였다!!!! WOW
import는 함수밖에서!
오늘 점심 윤쉐프...
갈수록 윤쉐프 먹기가 뭔가 힘들어지고 있다. 이것은 윤쉐프가 변해서가 아니라 내가 배불러서,,, 그리고 요즘 입맛이 별로 없어서겠죠,,,(근데 군것질은 잘함)ㅠㅠ
오늘은 꼭 마이페이지 시작하려고 했는데, 현실은 대댓글에서 끝났다. 그래도 대댓글 끝난게 어디야?! 거슬리는 에러창 하나만 아니면(????) 댓글/대댓글 작성, 조회, 수정, 삭제까지 가능...! 대댓글 처음에 구조를 잘못짜서 수정에서 막혀서 완전 뒤집어야 했다. 진짜 너무 헷갈려ㅠㅠ댓글에서도 props받고 대댓글(자신)의 것도 받아야하고... map은 정말 사랑스러운데 어려워... 점심 먹고 크로플 받는 퀴즈?갔다가 알고리즘 스터디 듣고나니 거의 오후 끝난 기분. 알고리즘 문제 풀려고 노력했지만 실패...! 오늘 알고리즘 수업은 더 열심히 들었는데, 약간 반쯤 정신이 나가있었다. 듣는데 무슨말인지 잘 모르겠는데 꾸역꾸역 넣으려고 노력하는 느낌ㅠ.. . 죄송합니다. 그래도 내가 풀던 코드 갖고 멘토님한테 갔더니 그걸로 나머지 어떻게 푸는지 알려주셔서 진짜 짜릿했다 꺄!~~~~~~~~~~~~~~~~~~~~내일 문제는 꼭... 풀리라 다짐하면서 버스 안에서 문제보면서 고민했는데 펜과 노트가 없으면 난 아무것도 할 수 없어,,, 였고. 집에 오니 다른 일하느라 밀려서 결국 못풀어봤다. 내일 일찍 가야지...진짜 내일은 일찍 갈거야.
대댓글 하다보니 해설지 같던 커피빈 멘토님 코드가 그리웠다... 하지만 이제 진짜 혼자 해야한다... 마켓에 들어와서부턴 사람들 진도도 다~ 다르고 구현 방법도 다 달라서 진짜 누구 잡고 알려줘욧!!!할 수도 없다.ㅠㅠㅠ 그리고 나도 구현한거여도 다른 분이 여쭤봐도 잘 대답 못한다,,, 슬프다...
아, 그리고 오늘 점심먹고 실버해피언니가 아이스초코 사주셨다~~~!!! >ㅁ< 근데 카페 이름이 기억이 안 나. 아이스초코는 가루가 뭉쳐있지만 맛있었다. 그러고보니 가방에서 크로플을 아직도 안꺼냈어. 상한 건 아니겠지... 아무튼 언니는 나한테 맨날 사주구 날 순수한 영혼,,,^^(???)으로 봐줘서 매우 좋다,,, >ㅅ< 그리고 오늘 PF리뷰도 봤는데 너무 따뜻하게 써주셔서 감사했고 조금 더 잘 써드릴 수 있었는데..! 후회했다. PF리뷰는 정말정말 좋은 제도야!!!!!!!!
맨날 땡치면 집가다가 어제 오늘 7시 30분쯤 나왔는데, 뭔가 일찍 나온 기분이었다. 평소보다 늦게 나온건데두...? 어쨌든 버스가 널널해서 좋고, 집에와서 쉬거나 그런 시간 없이 쭉 공부할 수 있어서 좋았다. 숙제를 끝내지 않고 집에 온거여서 마음이 약간 불안했는데 숙제랑 블로그도 생각보다 일찍 끝났다! (지금 시간 11시 46분~)
내일은 대댓글 오류까지 안 나게 하고 마이페이지 기능 구현하기가 목표~~~!!! 그 다음에 꾸미는 것도 차근차근 해보자... 헐 근데 내일 알고리즘 테스트자너..!?!?!!!!!!



'프론트엔드✏️ > 코드캠프' 카테고리의 다른 글
[문제] Do not add <script> tags using next/head 노랗고 긴 에러창 없애기 (0) | 2022.06.22 |
---|---|
알고리즘 - 크레인 인형뽑기 게임 (0) | 2022.06.22 |
알고리즘 - 실패율, indexOf, lastIndexOf, 배열을 객체처럼! (0) | 2022.06.21 |
220620 프론트엔드 부트캠프 41일차 : refreshToken, Graphql은 사실ㅇ0ㅇ (0) | 2022.06.20 |
220619 프론트엔드 부트캠프 : 주말, 카카오맵 마커 변경 (0) | 2022.06.20 |