개발하는거북이 어플 만들었어요

WEB/FE(HTML,CSS,JS | React)

[JavaScript | React] 이미지 파일 미리보기 구현

tedium._.dev 2023. 3. 7. 19:44

보통 이미지 업로드를 위해 해당 파일을 선택하면, 선택한 파일을 미리 보여주고는 한다. 이전에도 구글링을 해서 힌트를 얻었고 이후 더 간편한 구현 방식을 찾게 되어 기억해 놓았었는데, 최근에 똑같은 문제를 직면했을 때 그 방식이 떠오르지 않아서 이번에는 제대로 정리하고 넘어가고자 한다.

 

현재는 파일을 선택했을 때, 파일의 제목만 표시된다. 하지만 내가 원하는 것은 파일을 선택했을 때, 해당하는 이미지 파일의 url을 가져온 후 이를 img 태그의 src로 설정해주어 미리보기화 시키는 것이다.

 

만약 이를 위해 단순하게 input의 change 이벤트 핸들러로 value값을 통해 url에 접근하고자 하면, 해당하는 경로는 크롬의 보안 상 이슈로 fakePath 처리된다. 이용자가 임의로 이러한 방식을 통해, 파일을 탈취할 가능성도 있기 때문이다.

 

크롬 상의 보안으로 인해 경로가 fakepath 처리되었다

그렇기에 우리는 우회적인 방법이 필요한데, 첫 번째로는 fileReader를 이용한 방식이다.

 

첫 번째 방법 : FileReader 사용

import React, { useState } from "react";

export default function AdminBackground() {
  const [imageUrl, setImageUrl] = useState();
  return (
    <>
      {/* 이미지 파일의 url 있을 시 src로 넘겨 줌. */}
      {imageUrl && (
        <img
          src={imageUrl}
          alt="miribogi"
          className="w-96 absolute top-16 right-20"
        ></img>
      )}
      <form className="absolute right-0">
        <input
          type="file"
          onChange={(e) => {
            // 파일의 정보를 읽어들이기 위한 FileReader 생성.
            const reader = new FileReader();
            // FileReader을 통해 새로운 파일을 읽어왔을 때, 인자로 주어진 콜백함수를 실행하도록 설정.
            reader.onload = (fileInfo) => {
              // 로드된 파일의 정보를 인자로 받으면, 해당 인자의 .target.result를 통해 파일 url에 접근 가능.
              // 접근한 url을 state로 설정해 줌.
              setImageUrl(fileInfo.target.result);
            };
            // reader에 onload 설정이 끝났으니, 이제 reader를 통해 파일을 읽어 옴.
            reader.readAsDataURL(e.target.files[0]);
          }}
        />
      </form>
    </>
  );
}

뭐야 들여쓰기 왜이래

결과

아무튼, 아주 깔끔하게 처리되었다.

 

두 번째 방법 : URL.createObjectUrl API 사용

이 방식은 API의 메소드 그대로, 주어진 오브젝트를 토대로 새로운 url을 생성하는 방식이다. 인자로 해당 파일을 넘겨 주면 url을 리턴해 주므로, 이 url을 그대로 전달해주기만 하면 된다.

 

import React, { useState } from "react";

export default function AdminBackground() {
  const [imageUrl, setImageUrl] = useState();
  return (
    <>
      {/* 이미지 파일의 url 있을 시 src로 넘겨 줌. */}
      {imageUrl && (
        <img
          src={imageUrl}
          alt="miribogi"
          className="w-96 absolute top-16 right-20"
        ></img>
      )}
      <form className="absolute right-0">
        <input
          type="file"
          onChange={(e) => {
            const file = e.target.files[0];
            const url = URL.createObjectURL(file);
            setImageUrl(url);
          }}
        />
      </form>
    </>
  );
}

결과

이것도 역시 동일한 결과를 가져온다.

두 가지 방식은 조금씩의 차이가 존재하겠지만, 크게 다르지는 않으므로 입맛대로 적용하여 사용하면 될 것 같다. 그러나 나에게는 조금 더 코드가 간결한 후자의 방식이 조금 더 와닿는다.