React에서 기존의 데이터 흐름은 단방향으로, 부모 컴포넌트에서 자식 컴포넌트로 이동하지만 그 반대는 아닙니다. 그러나 자식 컴포넌트가 계층 구조를 거슬러 올라가 부모 컴포넌트에 정보를 전달할 수 있는 방법에 대한 의문이 제기됩니다.

애플리케이션의 상태를 수정하여 자식 요소가 부모 구성 요소에 정보를 전송할 수 있도록 하는 데 필요한 지식을 습득합니다.

React의 컴포넌트

각각의 부모 구조 안에 자식 요소가 포함된 React 컴포넌트의 계층적 조직은 애플리케이션의 UI 구성의 기반이 됩니다.

 <ParentComponent>
  <ChildComponent/>
</ParentComponent>

React의 컴포넌트 계층 구조에서 “자식” 컴포넌트라고 하는 각 개별 컴포넌트는 “부모” 컴포넌트라고 하는 상위 컴포넌트에 의해 “프로프”로 표시되는 정보를 제공받습니다. 프로퍼티에는 객체나 함수 같은 복잡한 구조부터 문자열 같은 단순한 구조까지 다양한 엔티티가 포함될 수 있습니다. 하지만 자식 컴포넌트 자체에는 이러한 데이터를 직접 변경할 수 있는 권한이 없기 때문에 원하는 수정을 위해서는 부모 컴포넌트를 통해 전달된 명령에 의존해야 합니다.

“CounterButton”이라는 특정 컴포넌트를 생각해 봅시다.

 const CounterButton = () => {
  const [count, setCount] = useState(0)

  const handleIncrement = () => {
    setCount(count + 1)
  }

  return (
    <button onClick={handleIncrement}>Increment</button>
  )
}

이 컴포넌트는 사용자가 버튼을 클릭할 때마다 증가되는 “카운트”라는 변수 지정을 보존합니다.

카운터버튼 컴포넌트를 “홈”이라는 큰 프레임워크 안에 캡슐화한다면, 두 컴포넌트의 전체 구조와 기능이 최적의 사용자 경험을 제공하기 위해 신중하게 조정되고 조화를 이룬다면 실행 가능한 디자인 선택으로 간주될 수 있습니다.

 const Home = () => {
  return (
   <CounterButton/>
  )
}

복잡한 문제를 해결하는 것은 문제 해결사로서의 인간의 본성에 내재되어 있습니다. 이 점을 설명하기 위해 카운터 버튼 컴포넌트에서 나오는 카운트 값을 홈 컴포넌트 프레임워크의 범위 내에 통합하려고 하는 시나리오를 생각해 보겠습니다. 이 경우 진행을 방해하고 성공을 방해할 수 있는 수많은 장애물이 발생할 수 있습니다. 하지만 결단력과 지략을 발휘하면 이러한 장애물을 극복하고 궁극적으로 역경을 이겨낼 수 있습니다.

이 글도 확인해 보세요:  판다와 폴라: 성능 대결

React는 데이터가 부모 컴포넌트에서 자식 컴포넌트로만 전송되는 단방향 데이터 흐름 패러다임을 고수합니다. 따라서 카운터버튼 컴포넌트는 공유 카운트 상태 값을 홈 컴포넌트에 직접 전송할 수 없습니다.

이 문제를 극복하기 위해서는 상태값을 상향 조정할 필요가 있습니다.

컴포넌트 간에 데이터를 공유하기 위해 상태를 올리는 방법

요소의 상태를 올리는 것은 상위 또는 상위 컴포넌트로 제어 및 소유권을 이전하여 요소의 계층 구조 내에서 해당 상태를 올리는 것을 포함합니다. 이 프로세스를 통해 프로그레시브 속성을 통해 업데이트된 데이터를 하위 컴포넌트에 전달할 수 있습니다.

이전 사례를 반복하려면 카운트 상태와 카운트를 증가시키는 함수(handleIncrement)를 홈 컴포넌트로 전송해야 합니다. 그런 다음 이 함수를 카운터 버튼 컴포넌트에 소품으로 전달해야 합니다.

 const Home = () => {
  const [count, setCount] = useState(0)

  const handleIncrement = () => {
    setCount(count++)
  }

  return (
    <CounterButton handlerIncrement={handleIncrement]/>
    <p>{count}</p>
  )
}

카운터 버튼 컴포넌트에서 원하는 기능을 구현하려면 핸들인크리먼트 함수를 통합하고 사용자가 버튼과 상호작용할 때 호출하는 방식으로 약간의 수정을 가해야 합니다.

 const CounterButton = ({handleIncrement}) => {
  return (
    <button onClick={handleIncrement}>Increment</button>
  )
}

상태 내 데이터에 대한 제어를 중앙 집중화함으로써 해당 상태 관리의 부담을 개인에서 부모 또는 보호자에게로 이전합니다.

상위 구성 요소 내에서 정보를 쉽게 표시할 수 있을 뿐만 아니라 상태를 올리면 다양한 관련 구성 요소 간에 데이터를 원활하게 조율하고 조화시킬 수 있습니다.

최상위 컴포넌트에 머리글과 바닥글 요소가 모두 포함되어 있고 그 자체가 상위 컴포넌트 내에 포함되어 있는 경우, 선호 속성을 통해 해당 정보를 전송함으로써 이들 간에 공유 데이터를 전달할 수 있습니다.

 const Home = () => {
  const [count, setCount] = useState(0)

  const handleIncrement = () => {
    setCount(count++)
  }

  return (
    <Header count={count}/>
    <CounterButton handlerIncrement={handleIncrement]/>
    <Footer count={count}/>
  )
}

제안의 힘을 활용할 때는 ‘소품 드릴링’이라는 바람직하지 않은 결과를 초래할 수 있으므로 주의해야 합니다.

소품 드릴링 문제

확장되는 소프트웨어 프로그램의 다양한 부분 간의 효율적인 커뮤니케이션을 보장하기 위해 심층적인 기능이 공통 리소스에 액세스해야 할 필요가 있을 수 있습니다. 그러나 이러한 요소의 계층적 구조로 인해 중간 계층을 통해 해당 정보를 전송해야 하는 경우가 많습니다. 안타깝게도 개별 속성을 통해 부모 노드에서 하위 컴포넌트로 데이터를 전달하는 이러한 관행은 ‘프로프 드릴링’으로 알려져 있으며, 시간이 지남에 따라 번거롭고 다루기 힘들어질 수 있습니다.

이 글도 확인해 보세요:  JES를 활용한 흥미로운 사운드 처리 기법 3가지

프로그래밍 언어로 프로퍼티 드릴링을 구현하면 정보 흐름을 모니터링하는 데 문제가 발생할 수 있으며, 그 결과 유지 관리가 어려운 복잡하고 번거로운 코드가 생성될 수 있습니다.

다양한 컴포넌트 간에 정보를 공유하면서 동시에 드릴링을 전파하는 문제를 완화하기 위해 React 컨텍스트를 활용하는 것이 실행 가능한 해결책이 될 수 있습니다. 이 방법론을 사용하면 상태를 중앙 집중화하여 애플리케이션 전체에서 액세스할 수 있습니다.

프로퍼티를 이용한 React의 데이터 공유

하위 엘리먼트에서 상위 엘리먼트로 정보를 전달하기 위해서는 하위 엘리먼트의 데이터 상태를 상위 엘리먼트 수준으로 올리고, 그 상태를 하위 엘리먼트에 업데이트하는 기능을 어트리뷰트로 제공해야 합니다.

하위 엘리먼트가 컴포넌트의 계층 구조에 깊숙이 포함되는 상황을 고려할 때, React Context와 같은 상태 관리 메커니즘이나 React Redux와 같은 외부 유틸리티를 사용하면 흔히 ‘프로프 드릴링’이라고 불리는 과도한 프로프 전달 문제를 완화할 수 있습니다.

By 박준영

업계에서 7년간 경력을 쌓은 숙련된 iOS 개발자인 박준영님은 원활하고 매끄러운 사용자 경험을 만드는 데 전념하고 있습니다. 애플(Apple) 생태계에 능숙한 준영님은 획기적인 솔루션을 통해 지속적으로 기술 혁신의 한계를 뛰어넘고 있습니다. 소프트웨어 엔지니어링에 대한 탄탄한 지식과 세심한 접근 방식은 독자에게 실용적이면서도 세련된 콘텐츠를 제공하는 데 기여합니다.