😁Next.js에 적용했지만, React에서도 동일하게 적용 할 수 있는 예제입니다.😁
(Next.js는 React에서 SSR을 사용 할 수 있도록 해주는 웹 개발 프레임워크이기 때문에 React랑 똑같기 때문에)
위 블로그를 참고하여 구현 하였다.
1. 화면 UI 만들기
- CSS는 styled-components 라이브러리를 사용했다.
- input 태그는 안예뻐서 label 태그를 사용해서 커스텀 해주었다.
실행 시켜보면 아래와 같이 출력된다.
더보기
import { useState } from "react";
import styled from "styled-components";
const Test = (props) => {
return (
<File>
<img className="previewImg" />
{/* label 태그의 for 속성과 input 태그의 id 속성의 값이 일치하면 label을 클릭 했으 때 file 기능이 동작한다. */}
<div className="file">
<label htmlFor="imgFile">이미지 업로드</label>
<input type="file" name="imgFile" id="imgFile" />
</div>
</File>
);
};
const File = styled.div`
margin: 20px;
.previewImg {
background: #efefef;
width: 150px;
height: 150px;
}
.file {
label {
width: 150px;
height: 30px;
background: tomato;
text-align: center;
line-height: 32px;
border-radius: 8px;
margin-top: 10px;
}
input {
display: none;
}
}
`;
export default Test;
2. state 추가하기
이미지 미리보기를 할 때는 img 태그 > src 속성에 base64 인코딩 값이 필요하다고 한다.
+ file의 상태값도 필요하다 (결과적으로 업도르는 file의 정보를 사용하기 때문에)
(state를 사용해도 되고, 다른 상태 관리 라이브러리를 사용해도 된다고 한다.)
const Test = (props) => {
const [preview, setPreview] = useState(""); // 이미지 미리보기 파일 (base64)
const [file, setFile] = useState(null); // 이미지 파일 (file)
return (
<File>
<img className="previewImg" />
{/* label 태그의 for 속성과 input 태그의 id 속성의 값이 일치하면 label을 클릭 했으 때 file 기능이 동작한다. */}
<div className="file">
<label htmlFor="imgFile">이미지 업로드</label>
<input type="file" name="imgFile" id="imgFile" />
</div>
</File>
);
};
3. onChange 구현
사용자가 이미지를 변경 할 때마다 실행될 함수가 필요하고, 그에 맞는 핸들러가 필요하다.
- handleCHangeFile 함수 등록
- input 태그에 onChange 속성 추가
const Test = (props) => {
const [preview, setPreview] = useState("/img/img.jpg"); // 이미지 미리보기 파일 (base64)
const [file, setFile] = useState(null); // 이미지 파일 (file)
const handleChangeFile = (e) => {
const reader = new FileReader();
const file = e.target.files[0];
reader.onloadend = () => {
// 2. 읽기가 완료되면 아래 코드가 실행됩니다.
const base64 = reader.result;
if (base64) {
setPreview(base64.toString()); // 파일 base64 상태 업데이트
}
};
if (file) {
reader.readAsDataURL(file); // 1. 파일을 읽어 버퍼에 저장 합니다.
setFile(file); // 파일 상태 업데이트
}
};
return (
<File>
<img className="previewImg" src={preview} />
{/* label 태그의 for 속성과 input 태그의 id 속성의 값이 일치하면 label을 클릭 했으 때 file 기능이 동작한다. */}
<div className="file">
<label htmlFor="imgFile">이미지 업로드</label>
<input
type="file"
name="imgFile"
id="imgFile"
onChange={handleChangeFile}
/>
</div>
</File>
);
};
4번부터는 블로그 참고 X
(추가적으로 필요한 기능들이 어떤 게 있을까 생각하다가 추가 되었다.)
4. 위 코드에서는 이미지 확장자가 아닌 파일을 넣더라도
경고창 없이 파일이 삽입되고 아래와 같이 출력된다.
이를 보고 예외 처리가 필요하겠다고 판단했고, 아래와 같이 handleChangeFile 함수를 수정했다.
const handleChangeFile = (e) => {
const reader = new FileReader();
const file = e.target.files[0];
//😜 확장자 확인
const extension = e.target.value.split(".")[1];
reader.onloadend = () => {
//😜 확장자 예외 처리
if (
extension === "png" ||
extension === "jpg" ||
extension === "jpeg" ||
extension === "gif"
) {
const base64 = reader.result;
if (base64) {
setPreview(base64.toString()); // 파일 base64 상태 업데이트
}
}
};
if (file) {
reader.readAsDataURL(file); // 1. 파일을 읽어 버퍼에 저장 합니다.
//😜 확장자 예외 처리
if (
extension === "png" ||
extension === "jpg" ||
extension === "jpeg" ||
extension === "gif"
) {
setFile(file); // 파일 상태 업데이트
} else {
alert("이미지 파일이 아닙니다.");
return;
}
}
};
'더 알아보기 > 기능' 카테고리의 다른 글
[react-datepicker] 달력 만들기_v1 (0) | 2022.03.29 |
---|---|
[React] 다음 주소 API 적용하기 (0) | 2022.03.28 |
[Editor] String 형태의 HTML 렌더링 하기 (2) | 2022.03.23 |
[Editor] Quill 에디터 적용하기 (0) | 2022.03.23 |
Zustand 사용하기 (0) | 2022.03.21 |
댓글