[NextJS] 이미지 피커 컴포넌트 만들기

나윤빈·2024년 7월 10일
0

Next.js

목록 보기
6/8
post-thumbnail

📚 커스텀 이미지 피커 입력 컴포넌트 만들기

// components/meals/image-picker.js
"use client";

import Image from "next/image";
import { useRef} from "react";

import classes from "./image-picker.module.css";

export default function ImagePicker({ label, name }) {
  // useRef 훅을 사용하여 ref를 생성하고
  const imageInput = useRef();

  // 숨겨진 input 클릭을 다루는 함수
  function handlePickClick() {
    // ref를 사용하여 click() 메서드 작동
    imageInput.current.click();
  }

  return (
    <div className={classes.picker}>
      {/* label을 props로 받아와 출력, htmlFor 속성을 추가하고 props로 name을 받아와 input id에 연결 */}
      <label htmlFor={name}>{label}</label>
      <div className={classes.controls}>
        <input
          className={classes.input} // hidden 속성으로 input을 가려줌
          type="file"
          id={name} // input id를 name으로 설정해 label과 연결
          accept="image/png, image/jpeg"
          name={name} // name: 업로드된 이미지를 추출하는데 필요
          ref={imageInput} // ref 속성값으로 사용해 연결
          onChange={handleImageChange}
          required
        />
        {/* button은 숨겨져있는 input을 클릭해야함 */}
        <button
          className={classes.button}
          type="button" // type을 설정하지 않으면 근처 form 자체를 제출함 
          onClick={handlePickClick}
        >
          Pick on Image
        </button>
      </div>
    </div>
  );
}

onClick 의 값으로 설정할 수 있는 이벤트핸들러는 서버 컴포넌트에서 사용할 수 없다. 클릭과 같은 상호작용은 브라우저, 클라이언트 컴포넌트에서 이루어지기 때문에 use client 지시어를 사용해 클라이언트 컴포넌트로 지정해줘야 한다.

📚 이미지 피커에 미리보기 추가하기

// components/meals/image-picker.js
"use client";

import Image from "next/image";
import { useRef, useState } from "react";

import classes from "./image-picker.module.css";

export default function ImagePicker({ label, name }) {
  // 선택된 이미지를 관리하는 state
  const [pickedImage, setPickImage] = useState();

  // useRef 훅을 사용하여 ref를 생성하고
  const imageInput = useRef();

  // 숨겨진 input 클릭을 다루는 함수
  function handlePickClick() {
    // ref를 사용하여 click() 메서드 작동
    imageInput.current.click();
  }

  // 이미지 선택을 다루는 함수: input에 이벤트 변화가 있을 때 사용
  function handleImageChange(event) {
    const file = event.target.files[0]; // 한 개의 파일만 선택

    // 파일을 선택하지 않았을 때
    if (!file) {
      setPickImage(null);
      return;
    }

    // DataURL 생성하기
    const fileReader = new FileReader();
    fileReader.onload = () => {
      setPickImage(fileReader.result);
    };
    fileReader.readAsDataURL(file);
  }

  return (
    <div className={classes.picker}>
      {/* label을 props로 받아와 출력, htmlFor 속성을 추가하고 props로 name을 받아와 input id에 연결 */}
      <label htmlFor={name}>{label}</label>
      <div className={classes.controls}>
        <div className={classes.preview}>
          {!pickedImage && <p>No image picked yet.</p>}
          {pickedImage && (
            <Image
              src={pickedImage} // 선택된 이미지 URL로 연결
              alt="The image selected by the user."
              fill
            />
          )}
        </div>
        <input
          className={classes.input} // hidden 속성으로 input을 가려줌
          type="file"
          id={name} // input id를 name으로 설정해 label과 연결
          accept="image/png, image/jpeg"
          name={name} // name: 업로드된 이미지를 추출하는데 필요
          ref={imageInput} // ref 속성값으로 사용해 연결
          onChange={handleImageChange}
          required
        />
        {/* button은 숨겨져있는 input을 클릭해야함 */}
        <button
          className={classes.button}
          type="button" // type을 설정하지 않으면 근처 form 자체를 제출함
          onClick={handlePickClick}
        >
          Pick on Image
        </button>
      </div>
    </div>
  );
}

이미지 미리보기를 위해서는 DataURL로 변환하는 것이 필요하다. 이러한 DataURL을 생성하기 위해 자바스크립트 내장 객체인 FileReader()를 활용할 수 있다.

참고
Next.js & React - 완벽 정복 가이드

profile
프론트엔드 개발자를 꿈꾸는

0개의 댓글