[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을 찍어보면 다음과 같은 구조임을 확인할 수 있다.
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.result
를 string
으로 쓴다고 명시해야 된다.
그럼 다음과 같은 결과물이 나온다. 버튼을 누르면 익숙한 창이 뜨고, 사진을 누르면 그 아래에 사진이 표시 된다.
3. styled-components
를 이용한 버튼 디자인
위에서 div
에 name="uploadFile"
을 설정한 것은 구린 버튼을 디자인하기 위함이었다.
위의 구린 버튼을
이렇게 바꿀 수 있다.
원리는 간단하다.
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는
label
에for
속성을 쓸 수 없으므로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
을 쓰는 중이어서 수작업으로 완전히 같게 구현하진 못했지만, 최대한 비슷해보이게 짰다.
사용자들에게는 육안으로 차이가 느껴지지 않을 것 같다. 😊
오늘 하루 종일 한 게 무엇인가 골똘히 생각해본다. 삽질, 삽질, 삽질, 예뻐진 버튼… 예뻐진 버튼이나 안고 자야겠다…
Leave a comment