[React+TypeScript] 사진 첨부 기능 추가

사진 첨부 기능 추가

사진을 첨부하고 미리보기 이미지를 띄우기 위해 삽질했던 결과물을 정리해서 올려본다.

1. 사진 첨부 코드

<div name="uploadFile">
  <input type="file"
    accept='image/jpg,image/png,image/jpeg,image/gif'
    name='profile_img'
    onChange={(e: any) => {
      convertFileToBase64(e.target.files[0]);
    }}
  />
</div>

e.target.files는 console을 찍어보면 다음과 같은 구조임을 확인할 수 있다.

image

2. 첨부한 파일을 이미지 url로 변환하는 코드

const convertFileToBase64 = (file: any) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    return new Promise((resolve: any) => {
      if (reader) {
        reader.onload = () => {
        setImage(reader.result as string);
        resolve();
        };
      }
    });
  };

TypeScript를 사용하므로 reader.resultstring으로 쓴다고 명시해야 된다.

그럼 다음과 같은 결과물이 나온다. 버튼을 누르면 익숙한 창이 뜨고, 사진을 누르면 그 아래에 사진이 표시 된다.

image

3. styled-components를 이용한 버튼 디자인

위에서 divname="uploadFile"을 설정한 것은 구린 버튼을 디자인하기 위함이었다.

위의 구린 버튼을

2022-07-12 23;59;09

이렇게 바꿀 수 있다.

원리는 간단하다.

input="file" 자체가 위에서 볼 수 있듯이 파일 첨부 버튼과 옆의 파일명이 뜨는 부분이 한데 묶여있어서 따로 스타일만 건들 수 없기 때문에, 과감히 화면에서 지워버리고 대체할 새로운 버튼을 만들어서 연결하는 것이다.

새로 생성할 예쁜 버튼을 label for 속성을 주고, 기능만 남기고 보이지 않게 할 기존의 구린 녀석을 id 속성을 줘서 같은 값으로 연결시키고 꾸미면 된다.

이 때, 한 페이지 안에서 작업하고 싶어서 React의 제공 기능 중 하나인 styled-components를 이용했다.

그래서 새로 생성한 예쁜 버튼과 구린 녀석을 각각 UploadFileLabel, UploadFileInput이라는 임의의 컴포넌트로 생성했다.

다만 사진 첨부가 필요한 다른 페이지에도 쓰일 것 같아서, 스타일 부분의 코드는 팀원들과 상의 후 따로 공용 컴포넌트로 뺄 것 같다.

코드는 다음과 같다.

<div style=>
  <UploadFileLabel htmlFor="uploadFile">업로드</UploadFileLabel>
  <UploadFileInput type="file"
    id="uploadFile"
    accept='image/jpg,image/png,image/jpeg,image/gif'
    name='profile_img'
    onChange={(e: any) => {
      convertFileToBase64(e.target.files[0]);
      console.log(e.target.files);
    }}
  />
</div>

react는 labelfor 속성을 쓸 수 없으므로 htmlFor을 사용해야 된다.

아래는 스타일 부분이다.

const UploadFileLabel = styled.label`
  display: inline-block;
  padding: .5em .8em;
  font-size: inherit;
  line-height: normal;
  vertical-align: middle;
  cursor: pointer;
  border: 1px solid ${theme.palette.lightgray};
  border-radius: .25em;

  :hover {
    transition: 2ms ease-in;
    border-color: ${theme.palette.blue};
    color: ${theme.palette.blue};
  }
`
const UploadFileInput = styled.input`
  position: absolute;
  padding: 0;
  margin: -1px;
  clip:rect(0,0,0,0);
  border: 0;
`

clip 속성은 범위를 지정해서 자르는 속성이다. clip:rect(0,0,0,0); 으로 네모낳게 사방으로 잘라버리면 이 못생긴 녀석은 존재감이 완전히 사라지게 된다!

기존의 버튼들에 ant design을 쓰는 중이어서 수작업으로 완전히 같게 구현하진 못했지만, 최대한 비슷해보이게 짰다.

사용자들에게는 육안으로 차이가 느껴지지 않을 것 같다. 😊

오늘 하루 종일 한 게 무엇인가 골똘히 생각해본다. 삽질, 삽질, 삽질, 예뻐진 버튼… 예뻐진 버튼이나 안고 자야겠다…

Categories:

Updated:

Leave a comment