[Next.js] 이미지 미리보기
본문 바로가기
더 알아보기/기능

[Next.js] 이미지 미리보기

by 은돌1113 2022. 3. 24.

😁Next.js에 적용했지만, React에서도 동일하게 적용 할 수 있는 예제입니다.😁

(Next.js는 React에서 SSR을 사용 할 수 있도록 해주는 웹 개발 프레임워크이기 때문에 React랑 똑같기 때문에)

 

React 이미지파일 미리보기

이번에는 React 프로젝트에서 이미지 파일 미리보기 기능을 정리합니다. 음.. 좀더 상세히 말하면 웹사이트에서 이미지 파일을 업로드 하기전에! 웹사이트 상에 이미지를 출력하여 미리보기 하는

basketdeveloper.tistory.com

위 블로그를 참고하여 구현 하였다.


1. 화면 UI 만들기

 

- CSS는 styled-components 라이브러리를 사용했다.

- input 태그는 안예뻐서 label 태그를 사용해서 커스텀 해주었다.

 

[CSS] input type="file" CSS 적용하기

: file 폼 태그에 accept 속성으로 사용자가 첨부하려는 파일을 특정 할 수 있습니다. 간략하게 파일 첨부를 할 수 있는 태그입니다. input tyle="file" 같은 경우에 class, id 값을 명시해서 CSS로 효과를 적

eundol1113.tistory.com

 

실행 시켜보면 아래와 같이 출력된다.

더보기
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;
      }
    }
  };

댓글