React Lifting State Up(상태 끌어올리기)

유슬기·2023년 2월 2일
0

프론트엔드

목록 보기
38/64
post-thumbnail

React의 데이터 흐름

React는 기본적으로 단방향 데이터 흐름(하향식)을 따라 상위 컴포넌트에서 하위로는 전달할 수 있지만, 상향식(아래 → 위)으로는 전달할 수 없다.

하위 컴포넌트는 상위 컴포넌트로부터 전달받은 데이터의 형태 or 타입이 무엇인지만 알 수 있다.
(데이터가 state로부터 왔는지, 하드코딩으로 입력한 내용인지 알지 못함)

하위 컴포넌트를 통해 상위 컴포넌트의 상태를 변경하기

종종 동일한 데이터에 대한 변경사항을 여러 컴포넌트에 반영할 필요가 생긴다. 이 때, 하위 컴포넌트에서 데이터를 직접 상위로 전달하는 것은 단방향 데이터 흐름의 원칙에 부합하지 않는다.

단방향 데이터 흐름의 원칙에 부합하면서 하위 컴포넌트를 통해(클릭 이벤트 등) 상위 컴포넌트의 상태(State)를 변경하기 위해서는 다음과 같은 방법을 이용할 수 있다.

  • 상태를 변경시키는 함수(handler) 그 자체를 하위 컴포넌트에 props로 전달
  • 하위 컴포넌트에서 전달받은 상태 변경 함수를 실행

아래의 예제와 같은 방법을 상태 끌어올리기 라고 한다.

예제 1

ChildComponent 컴포넌트에서 ParentComponent의 value 상태를 변경하기

import React, { useState } from "react";

export default function ParentComponent() {
  const [value, setValue] = useState("날 바꿔줘!");

  const handleChangeValue = () => {
    setValue("보여줄게 완전히 달라진 값");
  };

  return (
    <div>
      <div>값은 {value} 입니다</div>
			{/* 하위 컴포넌트에 상태 변경 함수 자체를 props로 전달 */}
      <ChildComponent buttonClick={handleChangeValue}/>
    </div>
  );
}

function ChildComponent({buttonClick}) { // 구조분해할당으로 상위 컴포넌트의 props 전달받기
  const handleClick = () => {
    // 전달받은 상태 변경 함수를 실행
		buttonClick();
  };

  return <button onClick={handleClick}>값 변경</button>;
}

예제 2

NewTweetForm 컴포넌트에서 Twittler의 tweets 상태를 변경하기

import React, { useState } from "react";

const currentUser = "김코딩";

function Twittler() {
  const [tweets, setTweets] = useState([
    {
      uuid: 1,
      writer: "김코딩",
      date: "2020-10-10",
      content: "안녕 리액트"
    },
    {
      uuid: 2,
      writer: "박해커",
      date: "2020-10-12",
      content: "좋아 코드스테이츠!"
    }
  ]);
	// tweets 상태 변경 함수
  const addNewTweet = (newTweet) => {
    setTweets([...tweets, newTweet]);
  }; // 이 상태 변경 함수가 NewTweetForm에 의해 실행되어야 한다

  return (
    <div>
      <div>작성자: {currentUser}</div>
      {/* 하위 컴포넌트에 상태 변경 함수 자체를 props로 전달 */}
      <NewTweetForm onButtonClick={addNewTweet}/>
      <ul id="tweets">
        {tweets.map((t) => (
          <SingleTweet key={t.uuid} writer={t.writer} date={t.date}>
            {t.content}
          </SingleTweet>
        ))}
      </ul>
    </div>
  );
}

function NewTweetForm({ onButtonClick }) { // 상위 컴포넌트로부터 props 전달받기
  const [newTweetContent, setNewTweetContent] = useState("");

  const onTextChange = (e) => {
    setNewTweetContent(e.target.value);
  };

  const onClickSubmit = () => {
    let newTweet = {
      uuid: Math.floor(Math.random() * 10000),
      writer: currentUser,
      date: new Date().toISOString().substring(0, 10),
      content: newTweetContent
    };
    // 여기서 newTweet이 addNewTweet에 전달되어야 한다.
    // 전달받은 상태 변경 함수를 실행
    onButtonClick(newTweet);
  };

  return (
    <div id="writing-area">
      <textarea id="new-tweet-content" onChange={onTextChange}></textarea>
      <button id="submit-new-tweet" onClick={onClickSubmit}>
        새 글 쓰기
      </button>
    </div>
  );
}

function SingleTweet({ writer, date, children }) {
  return (
    <li className="tweet">
      <div className="writer">{writer}</div>
      <div className="date">{date}</div>
      <div>{children}</div>
    </li>
  );
}

export default Twittler;

profile
아무것도 모르는 코린이

0개의 댓글