[19-1] 이미지 프로세스 이해
[19-2] 이미지 업로드
[19-3] HTML 기본 FILE 태그 숨기기
[19-4] 이미지 검증
📂 이미지 업로드
📂 이미지 조회
💡 storage는 어디에 있나?
AWS,GCP,AZURE와 같은 클라우드 안에 있다.
📂 아폴로 업로드 라이브러리 설치와 세팅
1️⃣ 라이브러리 설치를 위해 터미널에 yarn add apollo-upload-client
입력해 설치해 설치
2️⃣ 아폴로 업로드는 타입스크립트 또한 지원해주는 라이브러리다. 따라서 타입을 설치 yarn add @types/apollo-upload-client --dev
를 입력
3️⃣ app.tsx에서 세팅
// app.tsx파일 // import 추가하기 import {createUploadLink} from "apollo-upload-client" // 세팅 함수 부분 const uplodLink = createUploadLink({ uri : "백엔드 주소" }) const client = new ApolloClient({ link : ApolloLink.from([uplodLink]), cache : new inMemoryCache(), })
4️⃣ 파일 업로드할 수 있도록 화면 그려주기
// 이미지 업로드 api 사용을 위한 쿼리 작성 const UPLOAD_FILE = gql` mutation uploadFile($file: Upload!) { uploadFile(file: $file) { url } } `; export default function ImageUploadPage(): JSX.Element { const [imageUrl, setImageUrl] = useState(""); const [uploadFile] = useMutation< Pick<IMutation, "uploadFile">, IMutationUploadFileArgs (UPLOAD_FILE); // 이미지 업로드 함수 const onChangeFile = async ( event: ChangeEvent<HTMLInputElement> ): Promise<void> => { const file = event.target.files?.[0]; // 배열로 들어오는 이유: <input type="file" multiple/>일때, 여러 개 업로드 가능하기 때문입니다. const result = await uploadFile({ variables: { file } }); console.log(result.data?.uploadFile.url); setImageUrl(result.data?.uploadFile.url ?? ""); }; return ( <> <input onChange={onChangeFile} type="file" /> <img src={`https://storage.googleapis.com/${imageUrl}`} /> </> );
💡 해당 url의 이미지를 보고싶다면
저장해둔 스토리지 주소의 뒤에 이미지 url을 적어주면 된다.
http://storage.goolgeapis.com/이미지url
📂 useRef 이용하기
HTML 태그를 선택할 때는 getElementId를 사용했다.
react에서는 HTML 태그에 접근을 도와주는 역할을 useRef가 하고 있다.
import { useRef } from 'react'; export default function ImageRefPage(): JSX.Element { const fileRef = useRef<HTMLInputElement>(null); }
<input style={{ display: "none" }} onChange={onChangeFile} type="file" ref={fileRef} />
useRef를 이용한 전체 코드
import { gql, useMutation } from "@apollo/client"; import { ChangeEvent, useRef, useState } from "react"; import { IMutation, IMutationUploadFileArgs, } from "../../../src/commons/types/generated/types"; const UPLOAD_FILE = gql` mutation uploadFile($file: Upload!) { uploadFile(file: $file) { url } } `; export default function ImageRefPage(): JSX.Element { const [imageUrl, setImageUrl] = useState(""); const fileRef = useRef<HTMLInputElement>(null); const [uploadFile] = useMutation< Pick<IMutation, "uploadFile">, IMutationUploadFileArgs (UPLOAD_FILE); const onChangeFile = async ( event: ChangeEvent<HTMLInputElement> ): Promise<void> => { const file = event.target.files?.[0]; // 배열로 들어오는 이유: <input type="file" multiple/>일때, 여러 개 업로드 가능하기 때문입니다. const result = await uploadFile({ variables: { file } }); setImageUrl(result.data?.uploadFile.url ?? ""); }; const onClickImage = (): void => { // 기존 방식 : document.getElementById("파일태그ID")?.click(); fileRef.current?.click(); }; return ( <> <div style={{ width: "50px", height: "50px", backgroundColor: "gray" }} onClick={onClickImage} 이미지 선택 </div> <input style={{ display: "none" }} onChange={onChangeFile} type="file" ref={fileRef} /> <img src={`https://storage.googleapis.com/${imageUrl}`} /> </> ); }
📂 이미지 유무와 사이즈 검증하기
const onChangeFile = async ( event: ChangeEvent<HTMLInputElement> ): Promise<void> => { const file = event.target.files?.[0]; // 검증 로직 if (typeof file === "undefined") { alert("파일이 없습니다."); return; } if (file.size > 5 * 1024 * 1024) { // 5MB alert("파일 용량이 너무 큽니다.(제한: 5MB)"); return; } // API 호출 로직 const result = await uploadFile({ variables: { file } }); setImageUrl(result.data?.uploadFile.url ?? ""); };
📂 이미지 확장자 검증하기
방법 1
const onChangeFile = async ( event: ChangeEvent<HTMLInputElement> ): Promise<void> => { const file = event.target.files?.[0]; ~~~ // 기타 검증 로직 생략 if (!file.type.includes("jpeg") && !file.type.includes("png")) { alert("jpeg 또는 png 파일만 업로드 가능합니다."); return; } ~~~ // API 호출 로직 생략 };
방법 2
<input style={{ display: "none" }} onChange={onChangeFile} type="file" ref={fileRef} accept="image/jpeg,image/png" // 띄어쓰기 없이 콤마(,)를 기준으로 작성합니다. // accept를 추가하면 지정되지 않은 확장자는 선택 자체가 불가합니다. />
💡 MB(메가바이트) KB(키로바이트) B(바이트)
1024B = 1KB
1024KB = 1MB