게시글 수정(이미지 수정 중점적으로)

개발공부·2023년 1월 27일
0

* 결과

▶ 텍스트는 텍스트 대로 수정, 이미지는 이미지대로 삭제, 수정(추가)할 것

1) 기존 이미지 삭제

2) 기존 게시글에서 이미지 등록(수정)

3) 추가한 이미지 삭제

4) 이미지 4개 이상 초과 시 알림

5) 게시글 최종 수정(텍스트 포함) * 게시글 수정 자세한 글

* 문제점

1) 배열 안에 여러 객체 존재 시 어떻게 그 값을 찾고 수정해야 하나?

[참고한 글](What am I doing wrong when filtering out data from a multi-level object?)

* 참고한 글의 내용 적용

const mainPosts = [
	{Images: [{id: 57, src: "어쩌구57"}, {id: 58, src: "저쩌구58"}], id:1, UserId: 1},
	{Images: [{id: 59, src: "어쩌구59"}, {id: 60, src: "저쩌구60"}], id:2, UserId: 1},
	{Images: [{id: 30, src: "어쩌구30"}, {id: 31, src: "저쩌구31"},  {id: 41, src: "저쩌구41"}], id:3, UserId: 2},
	{Images: [{id: 33, src: "어쩌구33"}, {id: 20, src: "저쩌구20"}], id:4, UserId: 3},
	{Images: [{id: 32, src: "어쩌구32"}], id:5, UserId: 3}
]

const findData = {PostId: 30, UserId: 1}

const testPost = data => {
    data.forEach(d => {
        d.Images = d.Images.filter(p => ![findData.PostId].includes(p.id))
    });
    return data
}

console.log(testPost(mainPosts))

* 결과

// PostId가 30인 경우를 제외한 나머지 값이 출력됨
[
	{Images: [{id: 57, src: "어쩌구57"}, {id: 58, src: "저쩌구58"}], id:1, UserId: 1},
	{Images: [{id: 59, src: "어쩌구59"}, {id: 60, src: "저쩌구60"}], id:2, UserId: 1},
	{Images: [{id: 31, src: "저쩌구31"},  {id: 41, src: "저쩌구41"}], id:3, UserId: 2},
	{Images: [{id: 33, src: "어쩌구33"}, {id: 20, src: "저쩌구20"}], id:4, UserId: 3},
	{Images: [{id: 32, src: "어쩌구32"}], id:5, UserId: 3}
]

* 코드에 적용

 deleteImagesSuccess: (state, action) => {
      const data = action.payload;
      const filteredData = (list) => {
        list.forEach((post) => {
          post.Images = post.Images.filter(
            (img) => ![data.PostId].includes(img.id)
          );
        });
        return list;
      };
      state.mainPosts = filteredData(state.mainPosts);
      state.deleteImagesLoading = false;
      state.deleteImagesComplete = true;
    }

2) file이름 변경하기

▶ 처음 게시글 만들 때 넣는 이미지(이미지이름.jpg)가 아닌 수정할 때 (revise이미지이름.jpg) 이런 식으로 이름을 넣고 싶음

참고 글

const image = e.target.files;
image.name = revise${e.target.files[0].name};
const imageFormData = new FormData();
[].forEach.call(image, (value) => {
imageFormData.append("image", value, image.name); //세 번째 인자에 바꿀 이름 넣기
});

3) FormData로 게시글에 정보를 보내는데 계속 undefined로 나옴

  const image = e.target.files;
    const formData = new FormData();
    [].forEach.call(image, (value) => {
      formData.append("image", value);
    });
    formData.append("id", id);
    console.log("formData", formData);
    dispatch(reviseImageRequest(formData));

▶ router 부분에 upload 부분 추가

여러 개의 이미지 올릴 경우 : upload.array("image"),

하나의 이미지 올릴 경우 : upload.single("image"),

4) 전달 받은 이미지 값을 배열 내 객체 안에 넣고 싶다면?

조건 : 게시글의 아이디가 같을 것, 여기서 data.Images는 객체임

* 넣고자 하는 위치

const mainPosts = [Images: {}, UserId: 1, User: {id: 1, nickname: 'hello'}]
-> Images 안에 값을 넣고 싶음

* 넣고자 하는 데이터

const data = {PostId: 56, 
images: [
  {
    PostId: 56,
    id: 223,
	src: "cat_1674794570837.jpg"
  },
   {
    PostId: 56,
    id: 224,
	src: "cat2_1674794570844.jpg"
  },
]}

* 넣는 함수(유사 배열 이용)

유사배열 참고(제로초)

  const data = action.payload;
      const addData = (list) => {
        list.forEach((post) => {
          if(post.id === data.PostId) {
            [].forEach.call(data.findImage, (value) => {
              post.Images.push({id: value.id, src: value.src})
            })   
          }
        });
        return list;
      };
      state.mainPosts = addData(state.mainPosts);

4)-1 자세한 설명(기존 게시글에 이미지 넣기)

▶ 게시글 수정 시 이미지를 바로 올리고 삭제하도록 함

[components/PostCardContent.js]

 const onClickImageUpload = useCallback(() => {
    imageInput.current.click();
  }, [imageInput.current]);

  const onChangeImages = useCallback((e) => {   
    if(Object.keys(images).length >= 5) {
      alert('이미지는 4장까지만 추가됩니다.')
    } else {
      const image = e.target.files;
      if(Object.keys(image).length + Object.keys(images).length >= 5) {
        alert(`현재 등록한 이미지 수(${Object.keys(image).length}개)가 가능한 이미지 개수(${4 - Object.keys(images).length}개)보다 많습니다.`)
      } else {
        const formData = new FormData();
        [].forEach.call(image, (value) => {
          formData.append("image", value);
        });
        formData.append("id", id);
        dispatch(reviseImageRequest(formData));
      }
    }
    
return(
	  <div className="flex justify-center">
              <input
                type="file"
                name="image"
                multiple
                hidden
                ref={imageInput}
                onChange={onChangeImages}
              />
              <button
                type="button"
                onClick={onClickImageUpload}
                className="ml-4 mt-3 bg-light-beige rounded-md font-bold hover:bg-light-orange"
              >
                이미지 추가
              </button>
            </div>
)

[postSaga.js]

function reviseImageAPI(data) {
  return axios.patch("post/images/revise", data);
}

function* reviseImage(action) {
  try {
    const data = action.payload;
    const result = yield call(reviseImageAPI, data);
    yield put(reviseImageSuccess(result.data));
  } catch (error) {
    yield put(reviseImageFailure(error));
    console.log(error);
  }
}

[postSlice.js]

reviseImageSuccess: (state, action) => {
      const data = action.payload;
      console.log("data", data)
      const addData = (list) => {
        list.forEach((post) => {
          if(post.id === data.PostId) {
            [].forEach.call(data.findImage, (value) => {
              post.Images.push({id: value.id, src: value.src})
            })   
          }
        });
        return list;
      };
      state.mainPosts = addData(state.mainPosts);
      state.reviseImageLoading = false;
      state.reviseImageComplete = true;
    },

[routes/post.js]

▶ 이미지를 넣을 해당 게시글 찾기
▶ 게시글에서 이미지 넣기(upload.array("image") 필요)
▶ 이미지 등록 후 Image.findOne을 통해 찾기(여러 개를 찾아야 할 경우를 대비해 map 사용)

//이미지 삭제(수정 시)
router.delete("/images/:imageId", isLoggedIn, async (req, res, next) => {
  // DELETE /post/images/1
  try {
    const post = await Image.destroy({
      where: { id: req.params.imageId },
    });
    if (!post) {
      return res.status(403).send("게시글이 존재하지 않습니다.");
    }
    res.json({ PostId: parseInt(req.params.imageId) });
  } catch (error) {
    console.error(error);
    next(error);
  }
});

// 이미지 등록(수정 시)
router.patch(
  "/images/revise",
  isLoggedIn,
  upload.array("image"),
  async (req, res, next) => {
    // PATCH /post/images
    try {
      const post = await Post.findOne({ //이미지를 넣을 해당 게시글 찾기 
        where: { id: req.body.id },
      });
      if (!post) {
        return res.status(403).send("게시글이 존재하지 않습니다.");
      }
      if(req.files) {
        const images = await Promise.all( //게시글에서 이미지 넣기
          req.files.map((image) => Image.create({ src: image.filename }))
        );
        await post.addImages(images);
      }
    
      const findImage = await Promise.all( //이미지 등록 후 Image.findOne을 통해 찾기(이미지 삭제에도 영향)
        req.files.map((image) =>  Image.findOne({
          where: {src : image.filename},
          attributes: {
            exclude: ["createdAt", "updatedAt"],
          },
        }))
      )
      
      res.json({ PostId: parseInt(req.body.id), findImage: findImage });
    } catch (error) {
      console.error(error);
      next(error);
    }
  }
);
profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글