오늘은 useRef와 그것을 이용한 이미지를 받아오는 방법을 해보았다.
보통 브라우저에서 해당사이트의 정보들을 받아오는 과정중에서 가장 나중에 불러와지는것이 바로 이미지 부분이다.
이미지는 img src부분의 위치에 가서 받아오는 것인데, 이 src에는 사진전용컴퓨터? 라고도 할 수 있는 곳의 주소가 들어간다고 보면된다.
그곳까지 가서 받아오니 느리게 받아오는 것이다.
그럼 왜 따로 저장할까?
바로 용량문제때문이다.
일단 DB에 표 형식으로 저장된다고 보면 이미지는 BLOB이라는 타입으로 저장되게된다.
바이너리 라지 오브젝트의 준말인데,
왜 라지 라는 말이 붙었나?
사진을 확대하다보면 어느순간 사진이 깨져서 작은사각형형태로 보이게 된다. 이 각각의 하나하나에 rgb색상코드가 들어가고 그것은 0~255까지의 숫자로 표현된다. 그것이 수백, 수천개 모인것이 사진이고, 결국 이 전체는 숫자로 표현이 가능한데, 그만큼 용량을 많이 차지한다는 말이다.이것을 텍스트형태로 바꾸면 어마어마한 용량이 될 수도 있다.
영상또한 여러 사진들의 집합으로 볼 수 있기에 마찬가지의 결과를 가져온다.
그렇기에!
DB에 직접적으로 저장하지 않고, 사진전용? 컴퓨터에 저장을 해 그 주소로가서 다운받아오는 식으로 사용한다.
이것을 서비스로 제공하는 회사를 이용하면 된다.
아마존웹서비스:aws,
구글클라우드플랫폼:gcp,
마이크로소프트:azure
가 있다.
저 회사들을 클라우드 서비스를 제공하는 클라우더 프로바이더라고 한다.
현재 트랜드는 클라우드제공업체를 이용하는것이라고한다.
이미지업로드버튼만들기!
input태그의 type="file"을 사용하면 자동으로 클릭하는 버튼을 누르고 그 버튼을 클릭하게되면 내컴퓨터의 파일이 열려 그중에서 선택이 가능하다.
업로드 버튼을 클릭 ==> uploadfile로 mutation을 날림,게시물등록으로 createBoard로 API를 날리기 ===>
벡엔드로. 벡엔드에선 이미지 파일을 숫자나 텍스트로 바꿔 클라우드에 저장, 클라우드에서는 그 주소를 반환,createBoard를 받아 게시판생성 ====>DB에 테이블로 저장되면 imgurl부분에 해당클라우드에서 받아온 주소가 들어감.
클라우드에서 받아온 주소가 image의 src부분에 들어가는 것.
onChange부분에는 선택한 파일 이름이 들어가게된다.
업로드단계부터가 mutation을 날려주는 부분이다.
useMutation<여기는 결과타입, 여기는 variables의 타입>
이미지 뮤테이션을 날리기 전에 꼭 해야하는 과정이 있다.
포트폴리오용에는 같이 해놨으나 과제용폴더에는 깜빡잊어 곤혹을치렀다...
바로 아폴로 업로드클라이언트를 따로 설치하고, 그것에관해 세팅까지 해줘야 한다는 것이다.
yarn add apollo-upload-client
그리고 이것에 관한 타입스크립트도 존재하니 같이 설치 해준다.
yarn add @types/apollo-upload-client --dev
아폴로 세팅은 일전에 따로 컴포넌트를 분리해놨었다.
components ==> commons ==>apollo에 들어가 세팅을 마무리해준다.
import { createUploadLink } from "apollo-upload-client";
apollo-upload-client에서 createUploadLink를 import 하고,
createUploadLink를 번수에담아 본래의 client에 있던 uri를 옮기고 그 uri를 link라는것으로 받는데
link: ApolloLink.from([uploadLink]),
ApolloLink라는 것은 아폴로 클라이언트에서 임폴트 해오고, from에 link로 연결해주는 것을 배열로 받기에 대괄호안에 createUploadLink를 담은 변수를 넣어주면된다. 현재는 연결할것이 하나뿐이기에 하나만 들어간다.
이 설정을 해주지 않으면,, 쿼리문을 작성했다고 하더라도
이렇게..url을 가져오지 못하는것을 볼 수 있다.
한참헤매다가 블로깅하면서 정리하다가 깨달았다...
진짜 왜이럴까..
연결을 다해주고 img태그로 화면에 그려주는데 , src의 앞쪽에는 클라우드 스토리지주소가 들어가야한다.
띄어쓰기, 스펠링 주의.
input type="file" 에 관해 더 알아보니 브라우저별로 나타나는 모양이 다르다는것을 알았다.
그런데 이 UI는 수정할 수 없다.
수정을하려면 이 태그를 눈에서 안보이게하고 useRef를 사용해 연결하면 되는데, (for속성을 사용하는 방법도 있는것 같다) ref는 레퍼런스라는 말로 참조한다는 의미, 변수에 태그를 담을 수 있게 해준다.
즉
const qqq = useRef()
이렇게 하고 담을 태그안에 ref{qqq}
이런식으로 적어주면 그 태그를 qqq라는 변수에 담을 수 있다.
qqq.click()
하면 그 태그가 클릭되고, qqq.change()
하면 그 태그를 onchange할 수 있다.
*ref={qqq}에 빨간줄이 뜨는 이유 ==> 초기값문제
==> const qqq = useRef() 여기 소괄호를 아무것도 안넣지 말고 null을 넣음.
즉, const qqq = useRef(null)로
실제 실무에서는 저 변수 이름을 뒤에 Ref를 붙여 사용한다.
가짜버튼으로 할 태그와 연결하기
태그는 버튼이든, 이미지든 상관없음.
input테그를 가정하고
const onClickImg = () =>{
qqq.current?.click() ===> 현재있는 qqq가 있으면 클릭해줘.(옵셔널 체이닝 ?. 사용하지 않으면 빨간줄생김)
}
이미지 검증하기:
image vaildation이라고함.
mutation보내기전 즉, try문 전에 검증을 해야한다.
if 문을 사용해 file의 size가 없으면, 아래문 실행안함, 용량이 어느정도인지 제한등..
if 문으로 type.includes("jpg")이런식으로 막아주는 등을 할 수 있지만, 진짜버튼 즉 input type ="file" 에 accept라는 것을 주는 방식으로도 막아줄 수 있다.
accept에 적어줄경우 해당 확장자를 제외하고는 선택하지못하게 나오게된다. if문으로는 해당확장자가 아니면 알림창이뜨게 해줄 수 있다.
accept="image/jpg,..." 이렇게 쉼표로 구분해 사용하고, image/로도 쓰는것 같다.
그리고 .* ? 모든 파일을 선택할수도 있다고 한다.
상황에따라 다르게 사용하자.
이 검증부분도 import 로 따로떼어 사용할 수 있다.
commons의 라이브러리로빼서 함수로 작성한뒤 import 로 받아오고 return 부분은 원래 있던 컴포넌트의 try문실행을 막아주는것이니 함수안에 넣어준 if문의 조건들이 아니라면 return true 로 바꾸고 if 문의 조건에 맞는다면 return false를 하여 만든함수를 본문에 검증하는 부분에 (아까와 같은곳)넣고 변수에 담아 만약 받은 함수가 flase라면 return 해주는 식으로 작성한다.
변수명 === false 는 !변수명 으로 간단히 표현할 수 있다.
정리:
DB에는 url이 들어가고, 실제 파일은 스토리지(클라우드)에 들어간다! 따라서 조회해보면 url만 받아볼 수 있다.
용량계산
키로바이트 -> 메가바이트 -> 기가바이트...
각 1024 이다.
5MB를 기준으로 한다면 5 1024 하면 5KB, 거기에 또 *1024를 한다면 5MB가 된다.
참고자료를 받았는데 아직 훑어보기만했다. 다시 정리해가며 봐야겠다.