[React]부모-자식 컴포넌트간 함수 및 데이터 전달

devHagaa·2022년 2월 22일
0

React

목록 보기
4/9
post-custom-banner

👉 부모에서 자식으로 함수 전달 & 자식에서 부모로 데이터 전달


이번에 인프런에서 유튜브 클론코딩을 수강하다 부모->자식->자식의 함수 및 데이터 전달하는 부분이 있어, 추후에 참고용으로 또 보기위해 포스팅해두려 한다.


예시 코드를 간단히 설명하자면,
아래 코드에서 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>
  );
};
profile
디자이너인가 퍼블리셔인가 프론트엔드개발자인가 정체성의 혼란을 겪는 개린이
post-custom-banner

0개의 댓글