이번에 인프런에서 유튜브 클론코딩을 수강하다 부모->자식->자식의 함수 및 데이터 전달하는 부분이 있어, 추후에 참고용으로 또 보기위해 포스팅해두려 한다.
예시 코드를 간단히 설명하자면,
아래 코드에서 VideoDetailPage.js
는 영상의 상세페이지를 보여주는 컴포넌트이고, <Movie />
는 해당 동영상이 표시되는 영역, <CommentArea>
는 동영상 아래의 댓글 영역이다.
// VideoDetailPage.js (부모 컴포넌트)
import React, { useState } from "react";
import Axios from "axios";
import Comment from "./Sections/Comment";
export default function VideoDetailPage(props) {
const videoId = props.match.params.videoId;
// 해당페이지의 params에서 비디오 id를 저장
const [Comments, setComments] = useState([]);
// Comments(댓글)가 담길 빈 배열을 만들어준다.
const refreshFunction = (newComment) => {
// 자식컴포넌트에서 버튼을 클릭하면 자식에서 받아온 comment정보(새 댓글)를 newComment라고 한다.
setComments(Comments.concat(newComment));
// Comments(댓글)가 담긴 배열에 자식에서 받아온 newComment(새 댓글)를 추가한다.
};
return (
<Wrap>
<Movie />
<Comment
refreshFunction={refreshFunction}
commentLists={Comments}
postId={videoId}
/>
{/* Comment 컴포넌트(자식 컴포넌트)에 props로 댓글 추가함수(refreshFunction),댓글 목록의 정보(commentLists), 해당 게시글의 id(postId)를 넘겨준다. */}
</Wrap>
);
};
VideoDetailPage.js
에서 만든 refreshFunction
함수는 자식 컴포넌트에서 이벤트를 실행 할 수 있도록 props로 전달하고, 자식에서 클릭했을 때 실행할 동작을 선언한다.
// SingleComment.js (VideoDetailPage의 자식 컴포넌트 & Comment의 부모 컴포넌트)
import React, { useState } from "react";
import Axios from "axios";
import { useSelector } from "react-redux";
import SingleComment from "./SingleComment";
export default function Comment(props) {
const videoId = props.postId;
// 부모로부터 props로 전달받은 postId를 videoId라고 한다.
const user = useSelector((state) => state.user);
// 리덕스를 이용하여 로그인유저 정보를 가져옴
const [commentValue, setCommentValue] = useState("");
// textarea에서 작성한 댓글 내용이 저장됨
const onSubmit = (event) => {
event.preventDefault();
const variables = {
content: commentValue,
writer: user.userData._id,
postId: videoId,
};
Axios.post("/api/comment/saveComment", variables).then((response) => {
if (response.data.success) {
props.refreshFunction(response.data.result);
// 부모컴포넌트에 DB에 저장된 댓글정보를 전달해줌
setCommentValue("");
} else {
alert("코멘트를 저장하지 못했습니다.");
}
});
};
return(
<div>
<SingleComment
refreshFunction={props.refreshFunction}
comment={comment}
postId={videoId}
/>
{/* Comment 컴포넌트(자식 컴포넌트)에 props로 대댓글 추가함수(refreshFunction),댓글의 정보(comment), 해당 게시글의 id(postId)를 넘겨준다. */}
<form style={{ display: "flex" }} onSubmit={onSubmit}>
<textarea
style={{ width: "100%", borderRadius: "5px" }}
onChange={handleClick}
value={commentValue}
placeholder="코멘트를 작성해 주세요"
/>
<button style={{ width: "20%", height: "52px" }} onClick={onSubmit}>
Submit
</button>
</form>
</div>
);
};
VideoDetailPage.js
에서 props로 전달받듯이 자식컴포넌트로 전달할 때 props로 전달한다. 전달하는 값은 부모의 함수이므로 props.refreshFunction
로 적어준다.
// SingleComment.js (Comment의 자식 컴포넌트)
import React, { useState } from "react";
import Axios from "axios";
import { useSelector } from "react-redux";
export default function SingleComment(props) {
const user = useSelector((state) => state.user);
// 리덕스를 이용하여 로그인유저 정보를 가져옴
const [OpenReply, setOpenReply] = useState(false);
// 대댓글입력창 토글
const [CommentValue, setCommentValue] = useState("");
// 대댓글 입력내용
const onClickReplyOpen = () => {
setOpenReply(!OpenReply);
// 버튼을 클릭할 때마다 보였다 사라졌다함.
};
const onHandleChange = (event) => {
setCommentValue(event.currentTarget.value);
};
const onSubmit = (event) => {
event.preventDefault();
const variables = {
content: CommentValue,
writer: user.userData._id,
postId: props.postId,
responseTo: props.comment._id,
};
Axios.post("/api/comment/saveComment", variables).then((response) => {
if (response.data.success) {
console.log(response.data.result);
props.refreshFunction(response.data.result);
// 상위컴포넌트에 새로운 댓글목록을 다시 전달함.
setCommentValue("");
} else {
alert("코멘트를 저장하지 못했습니다.");
}
});
};
const actions = [
<span onClick={onClickReplyOpen} key="comment-basic-reply-to">
Reply to
</span>,
];
return (
<div>
<Comment
actions={actions}
author={props.comment.writer.name}
avatar={<Avatar src={props.comment.writer.image} alt />}
content={<p>{props.comment.content}</p>}
/>
{OpenReply && (
<form style={{ display: "flex" }} onSubmit={onSubmit}>
<textarea
style={{ width: "100%", borderRadius: "5px" }}
onChange={onHandleChange}
value={CommentValue}
placeholder="코멘트를 작성해 주세요"
/>
<br />
<button style={{ width: "20%", height: "52px" }} onClick={onSubmit}>
Submit
</button>
</form>
)}
</div>
);
};