프로젝트 중 상세 페이지 내에서 자신이 작성한 대댓글이나 댓글 수정하기 버튼을 누르면 해당 댓글의 정보를 해당 url 로 이동하면서 넘겨줘야하는 상황이 생겼습니다. usenavigate 기능 중 url 이동시 데이터를 같이 넘겨주는 기능이 있어 이를 적용했습니다.
데이터 넘길 때
//데이터 넘기기
import { useNavigate } from 'react-router-dom';
export default function Community() {
const navigate = useNavigate();
//navigate() 함수 안에 첫번째 인자로 이동하려는 url를 작성하고
//두번째 인자는 key가 state이며 value로 해당 url에 보내고싶은 데이터를 담아 객체 형태로 작성합니다.
//필자는 value를 배열형태로 보냈습니다.
// 댓글인지 대댓글인지 구분하는 배열[0], 댓글의 정보를 담는 배열[1]
return (
<CommentButton
onClick={() =>
navigate('/comment', {
state: [false, rp],
})
}
>
수정하기
</CommentButton>
)
데이터 받을 때
import { useNavigate, useLocation } from 'react-router-dom';
export default function CommentPage() {
//useLocation 으로 데이터를 받습니다.
const { state } = useLocation();
//받아온 state 데이터 가공
//댓글인지 대댓글인지 여부를 useState로 담았습니다..
const [isCommented, setIsCommented] = useState(state[0]);
//댓글에 대한 정보
const commentdata = state[1];
return (
);
}
프로젝트에 적용한 모습
//RecipeDetail.js 의 자식 컴포넌트 Community.js(댓글창 컴포넌트)
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import CommentValid from '../../components/Validation/CommentValidation';
import RecipeApi from './RecipeApi';
import tw from 'tailwind-styled-components';
export default function Community({ cocktailDetail, userInfo, getTime }) {
const navigate = useNavigate();
//생략
return (
<CommunityContainer>
<CommunityHeader>댓글을 작성해보세요!</CommunityHeader>
//생략
<div>
//cocktailDetail.comments 는 배열형태로 댓글 정보가 담겨있습니다.
{cocktailDetail.comments.map((ele) => {
return (
<>
<CommentContainer key={ele.userId}>
<CommentWriter>{ele.userName}</CommentWriter>
<CommentContent>{ele.content}</CommentContent>
<CommentAndButton>
<CommentDate>{getTime(ele.createdAt)}</CommentDate>
<ButtonContainer>
{ele.userId === userInfo.UserId && (
<>
<CommentButton
onClick={() => deleteComment(ele.commentId)}
>
삭제하기
</CommentButton>
//수정하기 버튼에서 state 를 배열로 넘겨준 모습
//state[0]는 댓글이면 true 대댓글이면 false 처리로
//댓글과 대댓글을 구분해줬다.
<CommentButton
onClick={() =>
navigate('/comment', {
state: [true, ele],
})
}
>
수정하기
</CommentButton>
</>
)}
<CommentButton
onClick={() => changeTag(ele.userId, ele.userName)}
>
답변하기
</CommentButton>
</ButtonContainer>
</CommentAndButton>
</CommentContainer>
{ele.replies.map((rp) => {
return (
<ReplyContainer key={rp.userId}>
<CommentWriter>{rp.userName}</CommentWriter>
<CommentContent>
{'@' +
rp.taggedUserInfo[0].taggedUserName +
' ' +
rp.content}
</CommentContent>
<CommentAndButton>
<CommentDate>{getTime(rp.createdAt)}</CommentDate>
<ButtonContainer>
{rp.userId === userInfo.UserId && (
<>
<CommentButton
onClick={() => deleteReply(rp.replyId)}
>
삭제하기
</CommentButton>
<CommentButton
onClick={() =>
navigate('/comment', {
state: [false, rp],
})
}
>
수정하기
</CommentButton>
</>
)}
<CommentButton
onClick={() => changeTag(rp.userId, rp.userName)}
>
답변하기
</CommentButton>
</ButtonContainer>
</CommentAndButton>
</ReplyContainer>
);
})}
</>
);
})}
</div>
</CommunityContainer>
);
}
const CommunityContainer = tw.div`
mt-24
`;
const CommunityHeader = tw.p`
text-xl
text-gray-200
text-center
font-bold
`;
const InputContainer = tw.div`
flex
p-4
my-5
border-[1px]
border-gray-300/50
text-xs
text-gray-200
items-end
max-md:flex-col
`;
const TagP = tw.p`
inline-block
px-2
py-1.5
mb-4
border-[1px]
border-gray-400
rounded-md
cursor-pointer
hover:text-white
hover:border-white
`;
const InputTextArea = tw.textarea`
h-24
w-full
bg-transparent
`;
const InputButton = tw.button`
h-8
w-20
ml-6
pb-0.5
border-[1px]
border-gray-400
rounded-md
inline-block
text-gray-400
hover:text-pointPurple-100
hover:border-pointPurple-100
max-md:mt-4
`;
const CommentContainer = tw.div`
flex-col
items-end
justify-between
py-3
border-b-[1px]
border-gray-300/50
max-md:flex-col
max-md:items-start
`;
const CommentWriter = tw.p`
text-gray-200
text-xs
`;
const CommentContent = tw.p`
text-gray-100
text-sm
`;
const CommentDate = tw.p`
mt-1.5
text-gray-200
text-xs
`;
const CommentAndButton = tw.div`
flex
justify-between
max-md:flex-col
`;
const ButtonContainer = tw.div`
mt-3
max-md:mt-0
max-md:text-right
`;
const ReplyContainer = tw(CommentContainer)`
ml-12
`;
const CommentButton = tw.button`
w-13
h-7
ml-2
border-[1px]
border-gray-400
rounded-md
text-xs
text-gray-400
px-2
hover:text-white
hover:border-white
max-md:ml-0
max-md:mr-1
max-md:mt-4
`;
//CommentPage /comment url 로 이동하면 보이는 컴포넌트
import React, { useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import tw from 'tailwind-styled-components';
import CommentValid from '../../components/Validation/CommentValidation';
// [
// {
// “commentId” : 1,
// “userId” : 1,
// “userName” : “kim”,
// “content” : “blah”,
// “replies” : [
// {
// “replyId” : 1,
// “userId” : 1,
// “userName” : “jjigae”,
// “taggedUserInfo” : [
// {
// “taggedUserId” : 2,
// “taggedUserName” : “kimchi”,
// }
// ],
// “content” : “shut up”,
// “createdAt” : 2000-00-00T00:00:00
// “modifiedAt” : 2000-00-00T00:00:00
// ],
// “createdAt” : 2000-00-00T00:00:00
// }
// ],
export default function CommentPage() {
const BASE_URL = process.env.REACT_APP_BASE_URL;
const { state } = useLocation();
const [isCommented, setIsCommented] = useState(state[0]);
const commentdata = state[1];
const [isValid, setIsValid] = useState(true);
const [comment, setComment] = useState(commentdata.content);
const [errorMsg, setErrorMsg] = useState(null);
const navigate = useNavigate();
console.log(state);
const handleSubmit = (e) => {
e.preventDefault();
CommentValid(comment, setIsValid);
//유효성검사가 통과되었다면
if (isValid) {
//댓글 수정이라면
if (isCommented) {
fetch(`${BASE_URL}comments/${commentdata.commentId}`, {
method: 'PATCH',
headers: {
//'ngrok-skip-browser-warning': 'true',
'Content-Type': 'application/json', // json fetch시
},
body: JSON.stringify({ content: comment }),
})
.then((data) => {
if (data.status === 200) {
// 응답이 성공적인 경우
console.log('요청이 성공했습니다.');
// console.log(data);
setErrorMsg(null);
navigate('/');
alert('수정했습니다!');
} else {
// 응답이 실패한 경우
console.log('요청이 실패했습니다.');
}
})
.catch((error) => {
console.log('에러', error);
navigate('/error');
});
//대댓글 수정이라면
} else {
fetch(`${BASE_URL}replies/${commentdata.replyId}`, {
method: 'PATCH',
headers: {
//'ngrok-skip-browser-warning': 'true',
'Content-Type': 'application/json', // json fetch시
},
body: JSON.stringify({
userId: commentdata.userId,
taggedUserId: commentdata.taggedUserId,
taggedUserName: commentdata.taggedUserName,
content: commentdata.content,
}),
})
.then((data) => {
if (data.status === 200) {
// 응답이 성공적인 경우
console.log('요청이 성공했습니다.');
// console.log(data);
setErrorMsg(null);
navigate('/');
alert('수정했습니다!');
} else {
// 응답이 실패한 경우
console.log('요청이 실패했습니다.');
}
})
.catch((error) => {
console.log('에러', error);
navigate('/error');
});
}
} else {
console.log('유효성검사에 걸렸습니다.');
setErrorMsg('1~200사이 글자로 입력해주세요');
}
};
return (
<div className="relative bg-gradient-to-r from-gradi-to to-gradi-from w-screen h-100% pt-[5rem] flex flex-col items-center ">
<button onClick={() => navigate('/')}>
<img
src="/images/logo.webp"
alt="로고"
className="w-[30px] mb-[2rem] "
/>
</button>
<section className="w-[520px] h-[520px] rounded-2xl bg-[#000000]/40 mb-[10rem] flex flex-col items-center">
<h1 className="mt-[30px] text-gray-200 font-bold text-[20px] mb-[2rem]">
댓글 수정
</h1>
{!isCommented && (
<p>@{commentdata[0].taggedUserInfo[0].taggedUserName}</p>
)}
<div>
<InputTextArea
placeholder="댓글을 입력하세요."
onChange={(e) => setComment(e.target.value)}
className={
!isValid
? 'border-red-500 border-[1px]'
: 'border border-solid border-gray-200 w-[400px] h-[200px] mb-[2rem]'
}
value={comment}
/>
{!isValid && (
<p className="text-red-500">1~200자 범위내로 작성해주세요</p>
)}
</div>
{errorMsg && <p className="text-error ">{errorMsg}</p>}
<InputButton onClick={handleSubmit}>전송하기</InputButton>
</section>
</div>
);
}
const InputTextArea = tw.textarea`
h-24
w-full
bg-transparent
`;
const InputButton = tw.button`
h-8
w-20
ml-6
pb-0.5
border-[1px]
border-gray-400
rounded-md
inline-block
text-gray-400
hover:text-pointPurple-100
hover:border-pointPurple-100
max-md:mt-4
`;
navigate 더 공부하기
'react' 카테고리의 다른 글
Redux, Recoil 비교하며 보는 Context API (0) | 2023.09.11 |
---|---|
Virtual DOM (1) | 2023.09.03 |
재사용성 높은 공통 컴포넌트 제작기 (0) | 2023.07.08 |
[ERROR]React Hook "useDispatch" cannot be called at the top level. (0) | 2023.04.29 |
[React] 상태 관리 (Redux) (0) | 2023.04.24 |