기존 내용이 포함된 채 게시글 수정하기(mysql 미연결)

개발공부·2022년 12월 14일
0

* 결과

- 단어 수정 시

- 게시글 수정 시
▶ 사진은 변경하지 않음(링크에 추가만 한 상황)
▶ 기존에 작성한 글에 내용을 추가하는 경우 변경할 수 있도록 함

  • 이전의 수정(단어 수정)
  • input에 placeholder에 이전 단어를 가져오고 새로운 단어 입력
    -> 새 단어 입력하지 않으면 기존 단어를 다시 입력하는 식

* 문제점

  • props로 수정 버튼을 누르면 수정 모달에 값을 전달 후 수정하려고 함
    -> props는 읽기 전용
    -> 이전의 게임에서 가져온 redux값들처럼 읽기 전용, props를 다룰 때 순수함수처럼 동작해야 함(state 요소)
    -> 이를 어떤 식으로 해결해야 할까?
  • redux에서 update_post_request
  • post id 찾고

    draft.mainPosts.find((v) => v.id === action.data.PostId).content = action.data.content

editMode는 true면 textArea를 보여주고 false면 기존 게시글을 보여줌
const [editMode, setEditMode] = useState(false)

description의 PostCardContent Component 만들고 editMode 추가

editMode일 때 ? textarea : 기존 값

postData는 고정값: 서버로부터 온 값

* 다르게 바꾸는 방법 생각해야 함

const [editText, setEditText] = useState(postData);
onChange={onChangeText}

const onChangeText = useCallback((e) => {
	setEditText(e.target.value);
})

수정 시 수정, 취소 버튼 한 개 더 필요

editMode를 false로 만들려면 onCancleUpdate, onChangePost는 부모 컴포넌트에서 조작해야 함

const onChangePost = useCallback((editText) => () => {
dispatch({
type: UPDATE_POST_REQUEST,
data: {
POSTId: post.id,
content: editText,
}
})
})

수정 버튼에 onClick={onChangePost(editText)}

* 이미지를 새로 업로드 할 경우(나중에 적용 예정)

이미 업로드된 이미지에 대한 데이터와 새로 업로드할 이미지에 대한 데이터 두 개로 분리해서 관리
-> 새로운 이미지 추가하는 것 + 기존 이미지 삭제하는 것도 대응 가능

* 적용

  • PostCard.js(Post 전체)
  • PostCardContent.js(PostCard.js의 내용부분)
  • postSlice.js(redux-toolkit)
  • postSaga.js(redux-saga)

[postSlice.js]

기존 initialState {
 mainPosts: [
    {
      id: shortId.generate(),
      content:
        "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
      User: {
        id: shortId.generate(),
        nickname: "test",
      },
      Images: ["https://picsum.photos/400"],
      Comments: [],
    },]
     revisePostLoading: false, //게시글 수정 중
  revisePostComplete: false,
  revisePostError: null,
  }
  
  //게시글 수정
    revisePostRequest: (state) => {
      state.revisePostLoading = true;
      state.revisePostError = null;
      state.revisePostComplete = false;
    },
    revisePostSuccess: (state, action) => {
      const data = action.payload;
      state.revisePostLoading = false;
      state.revisePostComplete = true;
      //data.id가 숫자이기 때문에 가능한 것
      state.mainPosts.splice(data.id, 1, {
        id: shortId.generate(),
        content: data.content,
        User: {
          id: shortId.generate(),
          nickname: "test",
        },
        Images: ["https://picsum.photos/500"], //임시
        Comments: [],
      });
    },
    revisePostFailure: (state, action) => {
      state.revisePostLoading = false;
      state.revisePostError = action.error;
    },

[postSaga.js]

function* revisePost(action) {
  try {
    const data = action.payload;
    yield put(revisePostSuccess(data));
  } catch (err) {
    console.error(err);
    yield put(revisePostFailure(err));
  }
}


function* revisePost_Req() {
  yield takeLatest(revisePostRequest.type, revisePost);
}

export const postSagas = [
  fork(revisePost_Req),
];

[PostCard.js]

const dispatch = useDispatch();
  const { mainPosts } = useSelector((state) => state.post);
  const [editMode, setEditMode] = useState(false);
  
    const onClickRevise = useCallback( //처음 수정 버튼 누름
    (e) => {
      setId(e.target.value);
      setEditMode(true);
    },
    [id]
  );

  const onRevisePost = useCallback( //textarea로 바뀌고 최종 수정 버튼 누름
    (editText, index) => () => {
      setEditMode(false);
      console.log("editText", editText);
      console.log("onRevisePost index", index);
      dispatch(revisePostRequest({ id: index, content: editText }));
    },
    [mainPosts]
  );

  const onCancleRevisePost = useCallback(() => {
    setEditMode(false);
  }, []);
  
  {mainPosts.map((post, index) => {
        return (
                  {editMode ? null : (
                    <Popover>
                      <>
                        <Popover.Button className="rounded-md px-3 py-2 text-base">
                          <div>
                            <EllipsisHorizontalIcon className="h-9 w-9" />
                          </div>
                        </Popover.Button>
                        <Transition
                          as={Fragment}
                          enter="transition ease-out duration-200"
                          enterFrom="opacity-0 translate-y-1"
                          enterTo="opacity-100 translate-y-0"
                          leave="transition ease-in duration-150"
                          leaveFrom="opacity-100 translate-y-0"
                          leaveTo="opacity-0 translate-y-1"
                        >
                          <Popover.Panel className="absolute mt-1 w-16 h-10">
                            <div className="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
                              <div className="bg-light-beige p-1">
                                <button
                                  value={index}
                                  onClick={onClickRevise}
                                  className="flow-root rounded-md px-2 py-2 transition duration-150 ease-in-out hover:bg-light-beige focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50"
                                >
                                  수정
                                </button>
                                <button
                                  value={index}
                                  onClick={onRemovePost}
                                  className="flow-root rounded-md px-2 py-2 transition duration-150 ease-in-out hover:bg-light-beige focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50"
                                >
                                  삭제
                                </button>
                              </div>
                            </div>
                          </Popover.Panel>
                        </Transition>
                      </>
                    </Popover>
                  )}
                </div>
              </header>

              <PostCardContent
                editMode={editMode}
                //아래의 값들 전달
                onCancleRevisePost={onCancleRevisePost} 
                onRevisePost={onRevisePost}
                image={post.Images}
                content={post.content}
                index={index}
              />
			...})

[PostCardContent.js]

import React, { useState } from "react";
import { useCallback } from "react";

const PostCardContent = ({
  image,
  content,
  editMode,
  onRevisePost,
  onCancleRevisePost,
  index,
}) => {
  const [editText, setEditText] = useState(content); //수정할 텍스트
  const onChangeText = useCallback((e) => {
    setEditText(e.target.value);
  });

  return (
    <>
      {editMode ? (
        <div>
          <img src={image} alt="post.Images" className="w-1/2 mx-auto block" /> 
          <textarea
            id="message"
            rows="4"
            className="ml-4 block p-2.5 w-11/12 h-full text-sm text-gray-900 bg-white rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
            onChange={onChangeText}
          >
            {content}
          </textarea>
          <div className="flex justify-end items-center mt-2 mr-4">
            <button
              onClick={onRevisePost(editText, index)} //editText와 index 값 전달
              className="mr-2 px-1 h-9 bg-light-beige rounded-md font-bold focus:bg-light-green focus:text-white"
            >
              수정
            </button>
            <button
              onClick={onCancleRevisePost}
              className="px-1 h-9 bg-light-beige rounded-md font-bold focus:bg-red-500 focus:text-white"
            >
              취소
            </button>
          </div>
          <small className="text-gray-400 m-4">2 hours ago</small>
        </div>
      ) : (
        <div>
          <img src={image} alt="post.Images" className="w-1/2 mx-auto block" />
          <p className="p-4">{content}</p>
          <small className="text-gray-400 m-4">2 hours ago</small>
        </div>
      )}
    </>
  );
};

export default PostCardContent;

* 참고

profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글