상태 끌어 올리기와 내려꽂기

</>·2021년 12월 1일
4

Get to Know React

목록 보기
7/8
post-thumbnail
post-custom-banner

목표

  • 상태 끌어올리기와 내려꽂기에 대해 알아본다.

1. 상태 끌어 올리기

1-1. 상태 끌어 올리기(state lifting up)

  const Id = () => {
    const [id, setId] = React.useState("");
    
    return (
      <>
        <div className="wrapper">
          <label htmlFor="id">ID: </label>
          <input id="id" />
        </div>
      </>
    );
  };

  const Pw = () => {
    const [pw, setPw] = React.useState("");
    
    return (
      <>
        <div className="wrapper">
          <label htmlFor="pw">PW: </label>
          <input type="password" id="pw" />
        </div>
      </>
    );
  };

  const App = () => {
    return (
      <>
        <Id />
        <Pw />
        <div className="wrapper">
            <button disabled={true}>
                Login
            </button>
        </div>
      </>
    );
  };
  • 위 코드는 아이디와 패스워드를 입력해 로그인을 할 수 있는 기능을 하는 부모(App) 컴포넌트와 자식(Id, Pw) 컴포넌트 그리고 로그인 버튼으로 이루어져있다.

🤔 의문

  • 현재 로그인 버튼은 disabled 상태인데, 아이디와 패스워드 모두 입력 됐을 때 어떻게 disabled 값을 false로 만들어 버튼을 활성화 시킬 수 있을까?

아이디와 패스워드 입력창에 값이 변경될 때마다 값을 setValue() 해주고 길이를 확인하여 둘 다 길이가 0이 아니면 활성화 해주면 된다.

const Id = () => {
  const [id, setId] = React.useState("");
    
  const onChangeId = (event) => {
    setId(event.target.value);
  };
    
    
  return (
    <>
      <div className="wrapper">
        <label htmlFor="id">ID: </label>
        <input id="id" onChange={onChangeId} />
      </div>
      </>
  );
};

const Pw = () => {
  const [pw, setPw] = React.useState("");

  const onChangePw = (event) => {
    setPw(event.target.value);
  };

  return (
    <>
      <div className="wrapper">
        <label htmlFor="pw">PW: </label>
        <input type="password" id="pw" onChange={onChangePw} />
      </div>
      </>
  );
};
  • 자식(Id, Pw) 컴포넌트의 값이 변경될 때마다 state 변수의 값을 변경해주는 onChangeIdonChangePw를 각각 선언해준다.
return (
  <>
    <Id />
    <Pw />
    <div className="wrapper">
      <button disabled={id.length === 0 || pw.length === 0}>
        Login
      </button>
    </div>
    </>
);
  • 그 후 버튼의 disabled 프로퍼티를 아이디 값의 길이와 패스워드 값의 길이를 조건으로 둘 중 하나라도 값이 입력되지 않으면 비활성화를 유지하면 된다.
  • 하지만, 자식(Id, Pw) 컴포넌트에 있는 아이디 값과 패스워드 값을 부모(App) 컴포넌트에서는 알 수 있는 방법이 없다.

🤔 의문

  • 그렇다면 자식 컴포넌트에 있는 id, pw state 변수를 어떻게 부모 컴포넌트에서 사용할 수 있을까?

여기서는 상태 끌어 올리기(state lifting up)라는 개념을 적용할 수 있다. 자세한 내용은 React 공식 문서에서 확인할 수 있다.

상태 끌어 올리기(state lifting up)

  • 하나의 컴포넌트에서 다른 컴포넌트의 state를 필요로 하면, 가장 가까운 공통 조상으로 state를 들어 올려 사용할 수 있다는 개념이다.
const App = () => {
    const [id, setId] = React.useState("");
    const [pw, setPw] = React.useState("");

    const onChangeId = (event) => {
      setId(event.target.value);
    };

    const onChangePw = (event) => {
      setPw(event.target.value);
    };

    return (
      <>
        <Id onChangeId={onChangeId} />
        <Pw onChangePw={onChangePw} />
        <div className="wrapper">
          <button disabled={id.length === 0 || pw.length === 0}>
            Login
          </button>
        </div>
      </>
    );
  };
  • 상태 끌어 올리기 개념을 적용하기 위해 자식(Id, Pw) 컴포넌트에 있는 아이디 값과 패스워드 값 그리고 함수들을 부모(App)컴포넌트로 들어 올린다.
  const Id = ({ onChangeId }) => {
    return (
      <>
        <div className="wrapper">
          <label htmlFor="id">ID: </label>
          <input id="id" onChange={onChangeId} />
        </div>
      </>
    );
  };

  const Pw = ({ onChangePw }) => {
    return (
      <>
        <div className="wrapper">
          <label htmlFor="pw">PW: </label>
          <input type="password" id="pw" onChange={onChangePw} />
        </div>
      </>
    );
  };
  • 그런 다음 각 자식 컴포넌트에 필요한 값이나 함수를 프로퍼티로 넘겨준다.

lifting_up


2. 프로퍼티 내리꽂기(Prop Drilling)

  • 프로퍼티 내리꽂기(Prop Drilling)란 프로퍼티를 필요로 하지 않는 하위 컴포넌트에도 전달하는 용도로만 쓰이며 다른 컴포넌트로 데이터를 전달하는 과정을 말한다.
const Toggle = () => {
  const [on, setOn] = useState(false);
  
  const onToggle = () => {
    setOn((prev) => !prev);
  }
  
  return (
    <>
      <Switch on={on} onToggle={onToggle} />
    </>
  );
};

const Switch = ({on, onToggle}) => {
  return (
    <div>
      <div>The button is {on ? 'on' : 'off'}</div>
      <button onClick={onToggle}>Toggle</button>
    </div>
  );
};
  • Switch 컴포넌트는 state 상태 변수와 onToggle 함수에 대한 참조가 필요하기 때문에 프로퍼티로 전달하였다.
const Switch = ({on, onToggle}) => {
  return (
    <div>
      <SwitchMessage on={on} />
      <SwitchButton onToggle={onToggle} />
    </div>
  )
}

const SwitchMessage = ({ on }) => {
  return <div>The button is {on ? 'on' : 'off'}</div>
}

const SwitchButton = ({ onToggle }) => {
  return <button onClick={onToggle}>Toggle</button>
}
  • 그리고 자식 컴포넌트인 SwitchMessage 컴포넌트와 SwitchButton 컴포넌트도 state 상태 변수와 onToggle 함수에 대한 참조가 필요하기 때문에 프로퍼티로 전달하였다. 이러한 과정을 프로퍼티 내려꽂기라고 한다.

🤔 의문

  • 한 두개의 컴포넌트에서 프로퍼티를 넘겨주는 것은 문제가 없다.
  • 하지만, 프로젝트 규모가 커지면서 하위 컴포넌트가 여러 계층이고 각 하위 컴포넌트마다 프로퍼티를 넘겨 준다면 추적하기 어려워지는 등 여러 문제가 발생한다.
  • 어떻게 해결해야 할까?

3. 해결하는 방법은요?

  • 위의 문제점을 해결하는 여러가지 방법이 존재한다. Context API, Redux, Mobx 등을 사용하여 전역으로 값을 관리할 수 있다.

출처

profile
개발자가 되고 싶은 개발자
post-custom-banner

1개의 댓글

comment-user-thumbnail
2021년 12월 6일

도움이 많이되었습니다:) 감사해요

답글 달기