[TIL] 9월 28,29일 ImageUpload(1)

기록하며 공부하자·2021년 9월 29일
0

웹사이트, 어플들 특히 게시판 기능이 있는 사이트를 이용하다 보면 이미지를 업로드할 경우가 많다.

일반적인 텍스트를 업데이트 하는것이 아니라서 파일형식, 용량등 신경써야 할부분이 많이 있다.

이미지 업로드의 기본적인 방식

이미지 업로드는 기본적으로 html input 태그의 속성으로 지원하고 있다.

<input type="file" />

이렇게 적용후 화면을 보면 input 버튼이 하나 나온다.

파일선택 버튼을 누르면 파일을 등록할수 있다.

input 태그 숨기기

html에서 제공하는 파일 업로드 버튼은 너무 못생긴 부분이 있다.

이부분을 스타일링 하려면 input 태그를 숨기고, 다른 div 혹은 이미지 부분을 클릭했을시 input 태그를 클릭할수 있도록 변경해 주어야 한다.

아래의 순서로 진행한다.

  1. input 태그를 숨긴다.
  2. useRef를 통해서 input 태그에 바인딩
  3. 바인딩한 값을 onClick에 담아서 div 태그에 바인딩

즉 div태그를 클릭시 숨긴 input 태그를 클릭하게 하도록 하는것이다.


 <input
        ref={fileRef}
        style={{ display: "none" }}
        type="file"
        onChange={onChangeFile}
      />

<LikeOutlined onClick={onClicUpload}>이미지 선택</LikeOutlined>
//ant design 이미지

등록 input 태그를 감추고, 좋아요 버튼으로 대체한 모습이다.

이미지 스토리지 저장소

보통 이미지는 일반 text db와는 다른 스토리지 저장소를 이용한다고 한다.
이미지 업로드시 스토리지 저장소에 저장하고 해당 게시글을 확인할때 스토리지 저장소에서 이미지 url을 받아와 페이지에 그려주는 방식이다.

여러가지 스토리지 저장소가 있지만 구글에서 제공하는 스토리지를 이용하였다.

https://storage.googleapis.com/${imageUrl}

${} 부분은 업로드한 이미지의 값을 state에 저장시킨후 바인딩 시킨 부분이다.

스토리지 저장소에 있는 이미지를 확인하려면 위와같은 형식이 되어야한다 이것을 img 태그에 src 부분에 넣어주면 이미지 미리보기가 가능해 진다.

<img src={`https://storage.googleapis.com/${imageUrl}`} />

이미지를 포함한 CreateBoard

createBoard 전체코드

import { gql, useMutation } from "@apollo/client";
import { useState, useRef } from "react";
import { LikeOutlined } from "@ant-design/icons";
const UPLOAD_FILE = gql`
  mutation uploadFile($file: Upload!) {
    uploadFile(file: $file) {
      url
    }
  }
`;
const CREATE_BOARD = gql`
  mutation createBoard($createBoardInput: CreateBoardInput!) {
    createBoard(createBoardInput: $createBoardInput) {
      _id
    }
  }
`;
export default function ImageUploadPage() {
  const [uploadFile] = useMutation(UPLOAD_FILE);
  const [createboard] = useMutation(CREATE_BOARD);
  const [imageUrl, setImageUrl] = useState("");
  const fileRef = useRef<HTMLInputElement>();
  async function onChangeFile(event) {
    const myFile = event.target.files[0];
    if (!myFile) {
      alert("파일이 없습니다.");
      return;
    }
    if (myFile.size > 5 * 1000 * 1000) {
      alert("파일 용량이 너무 큽니다.(제한 : 5mg");
      return;
    }
    if (!myFile.type.includes("jpeg") && !myFile.type.includes("png")) {
      alert("jpeg 또는 png만 업로드 가능합니다.");
      return;
    }
    const result = await uploadFile({
      variables: {
        file: myFile,
      },
    });
    console.log(result.data.uploadFile.url);
    setImageUrl(result.data.uploadFile.url);
  }
  function onClicUpload() {
    fileRef.current?.click();
  }
  function onChagneWriter(event) {
    setMyWriter(event.target.value);
  }
  function onChangePassword(event) {
    setMyPassword(event.target.value);
  }
  function onChangeTitle(event) {
    setMyTitle(event.target.value);
  }
  function onChangeContents(event) {
    setMyContents(event.target.value);
  }
  const [myWriter, setMyWriter] = useState("");
  const [myPassword, setMyPassword] = useState("");
  const [myTitle, setMyTitle] = useState("");
  const [myContents, setMyContents] = useState("");
  function onClickSubmit() {
    createboard({
      variables: {
        createBoardInput: {
          writer: myWriter,
          password: myPassword,
          title: myTitle,
          contents: myContents,
          images: [imageUrl],
        },
      },
    });
  }
  return (
    <>
      작성자: <input type="text" onChange={onChagneWriter} />
      <br />
      비밀번호: <input type="password" onChange={onChangePassword} />
      <br />
      제목: <input type="text" onChange={onChangeTitle} />
      <br />
      내용: <input type="text" onChange={onChangeContents} />
      <br />
      <input
        ref={fileRef}
        style={{ display: "none" }}
        type="file"
        onChange={onChangeFile}
      />
      <br />
      <LikeOutlined onClick={onClicUpload}>이미지 선택</LikeOutlined>
      <br />
      <img src={`https://storage.googleapis.com/${imageUrl}`} />
      <br />
      <button onClick={onClickSubmit}>저장하기</button>
      <br />
    </>
  );
}

이미지 파일을 포함해 게시글을 등록하려면 이미지 등록에 필요한 Mutation인 uploadFile을 작성해준후 createBoard variables 항목에 images를 포함해서 적어주면 된다.

profile
프론트엔드 개발자 입니다.

0개의 댓글