React, Next, Redux/⚛ React.JS

react + multer-s3 이미지 전송

DarrenKwonDev 2020. 7. 22. 04:02

https://darrengwon.tistory.com/91

https://darrengwon.tistory.com/317

 

 

1. 제출 버튼이 아니라 label을 눌러 버튼 형식으로 업로드하는 방식을 쓰려면 DOM을 조작해서 가상으로 제출 버튼을 누르게 만들어야 합니다.

 

(지금 생각해보니 이럴 때 쓰라고 있는게 useRef더군요... 아래 코드는 직접 DOM을 조작하는 방식으로 해버렸습니다만, 실전에선 재사용성을 위해 useRef를 사용합시다.)

 

2. formData로 전송해야 multer가 알아 듣습니다.

// 포토를 바꿨을 때, 제출을 위해 nextSibling을 DOM으로 불러 제출합니다.
const photoChange = (e) => {
  e.target.nextSibling.click();
};

// 제출되었을 때의 로직
const PhotoSubmit = (e) => {
  e.preventDefault();
  
  // formData로 전송해야 multer가 알아 듣습니다.
  const formData = new FormData();
  formData.append("file", e.target.childNodes[1].files[0]);
  
  axios.post("/api/image/profile", formData, {
    header: {
      "content-type": "multipart/form-data",
    },
  });
};
<form
  encType="multipart/form-data"
  style={{ position: "relative" }}
  onSubmit={PhotoSubmit}
>
  <Label htmlFor="file">이미지 변경</Label>
  <input
    type="file"
    name="file"
    id="file"
    accept="image/*"
    onChange={photoChange}
    required
    style={{ visibility: "hidden" }}
  />
  <input type="submit" style={{ display: "none" }}></input>
</form>

 

3. file이라는 키 값으로 전송했으므로 multer에서는 file이라는 이름으로 받으면 되겠습니다. single("file")

const uploadUserProfileImage = multer({
  storage: multerS3({
    s3,
    bucket: "cienps/user-profile-image",
    contentType: multerS3.AUTO_CONTENT_TYPE,
    acl: "public-read-write",
    shouldTransform: true,
    transforms: [
      {
        id: "user-image-resized",
        key: function (req, file, cb) {
          let extension = path.extname(file.originalname);
          cb(null, Date.now().toString() + extension);
        },
        transform: function (req, file, cb) {
          cb(null, sharp().resize(200, 200));
        },
      },
    ],
  }),
}).single("file");

 

끝! 업로드된 내용은 req.file에 전달됩니다.

apiRouter.post("/image/profile", uploadUserProfileImage, (req, res, next) => {
  console.log("uploaded", req.file);
});