카드 내에 존재하는 삭제 버튼이 눌렸을 때 카드의 이동하는 동작을 막고 싶었다.
stopPropagation()
으로 막는 방법
<DeleteCard
onClick={(e) => {
e.stopPropagation();
console.log("삭제");
}}
>
<MdDeleteForever size="25" style={{}}></MdDeleteForever>
</DeleteCard>
카드와 같은 부모요소를 가지도록(?) 나란히 작성해주고 부모요소가 static 외의 position을 가지고 있을 때 position: absolute
로 위치를 지정할 수 있다.
<CardBox done={`${study.isDone}`}>
<div
onClick={() => {
navigate(`/detailstudy/${study.id}`);
}}
>
<CardNav>
<div>작성자 {study.writer}</div>
</CardNav>
<Cardcontext>{study.title}</Cardcontext>
</div>
<MdDeleteForever
size="25"
onClick={() => console.log("삭제")}
style={{ position: "absolute", top: "10px", right: "10px" }}
></MdDeleteForever>
<Cardfooter>
<div>
<Button>{study.isDone ? "완료" : "미완료"}</Button>
</div>
</Cardfooter>
</CardBox>
CardList에서 prop으로 study라는 item을 내려보냈으니 study.id를 하면 해당 카드의 id를 알 수 있다!
이를 이용해서 클릭한 Card를 삭제하는 동작을 코딩했다.
const navigate = useNavigate();
const queryClient = useQueryClient();
const mutation = useMutation(deleteStudy, {
onSuccess: () => {
queryClient.invalidateQueries("study");
console.log("Delete 성공");
},
});
const findCardId = (e) => {
if (window.confirm("정말 삭제하시겠습니까??")) {
//확인
mutation.mutate(study.id);
alert("삭제되었습니다!");
} else {
return false;
}
};
detail페이지에서도 삭제기능을 동작해야 하고 코멘트도 삭제하는 기능이 필요하니 customhook으로 빼는 시도를 해봤다.
Card.jsx
const [deleteStudyMutation] = useDelete();
const findCardId = (e) => {
if (window.confirm("정말 삭제하시겠습니까??")) {
//확인
deleteStudyMutation.mutate(study.id);
alert("삭제되었습니다!");
} else {
return false;
}
};
useDelete
import { useMutation, useQueryClient } from "react-query";
import { deleteStudy } from "../api/studyTodo";
const useDelete = () => {
const queryClient = useQueryClient();
const deleteStudyMutation = useMutation(deleteStudy, {
onSuccess: () => {
queryClient.invalidateQueries("study");
console.log("Delete 성공");
},
});
return [deleteStudyMutation];
};
export default useDelete;
1. input을 customhook으로 만들어서 코드를 줄일 수 있다.
2. queryClient와 mutation을 사용하는 코드를 customhook으로 줄일 수 있을 것 같다.
3. useNavigate를 사용하는 곳도 customhook으로 만들어서 줄일 수 있을 것 같다.
studyTodo.js
const updateComplete = async (newComplete) => {
const response = await axios.patch(
`${process.env.REACT_APP_SERVER_URL}/study/${newComplete.id}`,
{ isDone: newComplete.isDone }
);
};
Button.jsx
const queryClient = useQueryClient();
const updateCompleteMutation = useMutation(updateComplete, {
onSuccess: () => {
queryClient.invalidateQueries("study");
},
});
const basicButtonHandler = (role) => {
if (role === "complete") {
const newComplete = { id: props.cardKey, isDone: !props.complete };
updateCompleteMutation.mutate(newComplete);
} else if (role === "filter") {
console.log("filter 및 정렬");
}
};
id와 새 내용을 인자로 넘겨서 값을 patch 해주었다.
detail페이지로 들어가면 코멘트가 db가 빈 값으로라도 생성되지 않기 때문에 오류가 발생하는 것 같다.
먼저, DetailTodo.jsx에서 오류 처리를 해주었다.
DetailTodo.jsx
return (
<>
<Header />
<DetailBox>
<h1>{`${study.title}`}</h1>
<div>
<div>{`작성자: ${study.writer}`}</div>
<Button>수정</Button>
<Button>삭제</Button>
</div>
<div>{`완료 여부: ${study.isDone}`}</div>
<div>{`내용 : ${study.contents}`}</div>
</DetailBox>
{comments ? (
<DetailBox>
{comments.userComments?.map((comment) => (
<Comments codata={comment} key={comment.user} />
))}
</DetailBox>
) : coisError ? (
<p>댓글 오류가 발생하였습니다!!</p>
) : coisLoading ? (
<p>댓글 로딩중</p>
) : (
<p>댓글을 불러오지 못했습니다.</p>
)}
<Footer />
</>
);
window.confirm
입력할 수 있는 공간 만들기 -> state를 하나 만들어서 true일 때 입력창 보여주기(기존 제목과 내용을 set) -> 저장 버튼을 눌렀을 때, db 업데이트 해주기
<>
<Header />
<DetailBox>
{!updateState && (
<>
<h1>{`${study.title}`}</h1>
<div>
<div>{`작성자: ${study.writer}`}</div>
<Button
onClick={() => {
setUpdateState(true);
setUpdateTitle(study.title);
setUpdateContent(study.contents);
}}
>
수정
</Button>
<Button>삭제</Button>
</div>
<div>{`완료 여부: ${study.isDone}`}</div>
<div>{`내용 : ${study.contents}`}</div>
{comments ? (
<div>
{comments.userComments?.map((comment) => (
<Comments codata={comment} key={comment.user} />
))}
</div>
) : coisError ? (
<p>댓글을 불러오지 못했습니다.</p>
) : coisLoading ? (
<p>댓글 로딩중</p>
) : null}
</>
)}
{updateState && (
<>
<div>
<label>제목</label>
<input value={updateTitle} onChange={updateTitleHandler} />
</div>
<div>
<label>내용</label>
<textarea value={updateContent} onChange={updateContentHandler} />
</div>
<Button
role={"update"}
update={newStudy}
onClick={() => {
setUpdateState(!updateState);
console.log("저장");
}}
>
저장
</Button>
</>
)}
</DetailBox>
<Footer />
</>
Button.jsx
전체 리스트와 상세 페이지 모두 변경되어야 하기 때문에 2가지를 무효화 해줬다.
// 게시글 업데이트
const updateDetailMutation = useMutation(updateStudy, {
onSuccess: () => {
queryClient.invalidateQueries("study");
queryClient.invalidateQueries(`${props.update.id}`);
},
});
// 동작되는 곳
<ButtonStyle
onClick={() => {
basicButtonHandler(props.role);
props.onClick();
}}
>
{props.children}
</ButtonStyle>
Put - 리소스의 모든 것을 업데이트 한다.
Patch - 리소스의 일부를 업데이트 한다.
오늘 통신 관련 작업을 많이 해보면서 axios와 좀 더 친숙해진 것 같다. 코멘트 로딩의 경우 따로 오류 처리를 해줬고 할 작업이 많은 update를 구현했고 댓글의 수정/삭제만 구현하면 필수 요구사항은 종료된다.