이 그림은 이미지를 업로드하기 위해, 브라우저와 프론트엔드서버, 백엔드서버, DB, 그리고 스토리지라는 공간에서의 데이터가 이동하는 그림이다.
프론트엔드
백엔드(API) 요청 ➡ 백엔드
➡ 파일전송 ➡ Storage
➡ 이미지 주소 ➡ 백엔드
➡ 프론트엔드
➡ 이미지 주소(API) 요청 ➡ 백엔드
➡ DB
💡Storage : 여러 컴퓨터들을 연결시켜 놓은 대용량 DB
1) 우선 사용하고 있는 백엔드서버의 이미지업로드 API는 uploadFile API
2) 아폴로 업로드 관련 클라이언트
apollo-upload-client
설치
(타입설치는yarn add @types/apollo-upload-client --dev
)
3) app.tsx 세팅
import {createUploadLink} from "apollo-upload-client" //세팅 함수 부분 const uplodLink = createUploadLink({ uri : "백엔드 주소" }) const client = new ApolloClient({ link : ApolloLink.from([uplodLink as inknown as ApolloLink]), cache : new inMemoryCache(), })
4) 파일 업로드를 위한 화면 그리기
// 이미지 업로드 api 사용을 위한 쿼리 작성 const UPLOAD_FILE = gql` mutation uploadFile($file:Upload!){ uploadFile(file:$file){ url} } ` //mutation 날리기 const ImageUPloadPage = ()=>{ const [uploadFile] = useMutation(UPLOAD_FILE) // 이미지 업로드 함수 const onchangeFile = async(e:ChangeEvent<HTMLInputElement>)=>{ //files는 없을수도 있기 때문에 옵셔널 체이닝 사용. //이미지는 배열로 들어가기 때문에 하나 선택하기 위해 0번째 인덱스 const Imagefile = e.target.files?.[0] try{ //선택한 사진을 Imagefile라는 변수에 담고, variables에 넣어 보내기 await uploadFile({ variables : {file : Imagefile} }) console.log(result.data?.uploadFile.url) } catch(error){ alert(error.message) }} return <input type="file" onChange={onChangeFile}/>}
5) 함수를 통해 이미지 파일 유무 / 사이즈 / 확장자 검증하기
const onchangeFile = async(e:ChangeEvent<HTMLInputElement>)=>{ const [uploadFile] = useMutation(UPLOAD_FILE) //사이즈 검증 if(!file?.size){ alert("파일이 존재하지 않습니다.") return } // 이미지 파일의 사이즈 크기 검증 if(file?.size > 5 * 1024 * 1024){ alert("파일 용량이 너무 큽니다.(제한: 5MB)") return } // 이미지 파일의 확장자 검증 if(!file.type.includes("png") && !file.type.includes("jpeg")){ alert("jpeg 파일 또는 png 파일만 업로드 가능")}
6) 이미지 검증 컴포넌트로 분리 가능(utils)
export const checkFileValidation = (file?: File)=>{ //이미지 검증 함수들 넣기.
import {checkFileValidation} from '파일경로' const ImageUPloadPage = ()=>{ const onchangeFile = async(e:ChangeEvent<HTMLInputElement>)=>{ const Imagefile = e.target.files?.[0] //이미지 검증 함수 const isValid = checkFileValidation(Imagefile) //이미지 검증의 결과값에 따라 업로드를 진행하거나 함수를 종료 if(!isValid)return
7) 기존 Input 태그 숨기기
1) label 태그와 htmlFor 사용
label 태그의 htmlFor 속성값을 이용해 똑같은 id를 찾아 그 태그의 기능을 연결
<div> //인풋태그 id "fileTag" 와 같은 기능을 실행하여 실행하기를 누르면 가능해짐 <label htmlFor="fileTag">실행하기</label> <img style={{ width: '500px' }} id="image" /> <input id="fileTag" type="file" onChange={readImage}></input> </div>
2) useRef() 기능 사용
https://velog.io/@nanyong0214/useRef-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
참조하기