React에서는 단방향 데이터 흐름이라는 원칙에 따라, 하위 컴포넌트는 상위 컴포넌트로부터 전달받은 데이터의 형태 혹은 타입이 무엇인지만 알 수 있다.
이러한 방식은 코드의 양을 줄이거나 단순화하려는 목적은 아닌다.
유지보수를 좀 더 편리하게 만들 수 있도록 해주는 역할을 한다.
단방향은 이처럼 관리하기 쉬운 특징뿐만 아니라 버추얼 돔(Virtual DOM)과 궁합이 잘 맞는다.
뷰를 통째로 바꾸어주는 역할을 하기 때문에 단방향 데이터 방식은 DOM을 갱신할 때 큰 장점이 있다.
컴포넌트 구조짜기
: 상향식
데이트 흐름
: 하향식
가끔 일부 컴포넌트가 동일한 변경 데이터를 보여줘야 할 필요가 있다.
이럴 때 공통 조상에 state를 끌어올리는 걸 권장한다.
상위
import { useState } from "react"; import Child1 from "../../../src/components/units/15-lifting-state-up/Child1"; import Child2 from "../../../src/components/units/15-lifting-state-up/Child2"; export default function CounterStatePage(): JSX.Element { // let count = 0 // let은 리액트 전용 html에서 변경을 감지하지 못함(따라서, state 써야됨) const [count, setCount] = useState(0); return ( <div> <Child1 count={count} setCount={setCount} /> <div>===========================</div> <Child2 count={count} setCount={setCount} /> </div> ); }
하위_1
export default function Child1(props: any): JSX.Element { const onClickCountUp = (): void => { props.setCount((prev: number) => prev + 1); }; return ( <div> <div>자식1의 카운트 : {props.count}</div> <button onClick={onClickCountUp}>카운트 올리기!!!</button> </div> ); }
하위_2
export default function Child2(props: any): JSX.Element { const onClickCountUp = (): void => { props.setCount((prev: number) => prev + 1); }; return ( <div> <div>자식2의 카운트 : {props.count}</div> <button onClick={onClickCountUp}>카운트 올리기!!!</button> </div> ); }
보통의 경우, state는 렌더링에 그 값을 필요로 하는 컴포넌트에 먼저 추가된다. 그러고 나서 다른 컴포넌트도 역시 그 값이 필요하게 되면 그 값을 그들의 가장 가까운 공통 조상으로 끌어올리면 된다.
다른 컴포넌트 간에 존재하는 state를 동기화시키려고 노력하는 대신 하향식 데이터 흐름에 기대는 걸 추천한다.
state를 끌어올리는 작업은 양방향 바인딩 접근 방식보다 더 많은 보일러 플레이트
코드를 유발하지만, 버그를 찾고 격리하기 더 쉽게 만든다는 장점이 있다.
어떤 state든 간에 특정 컴포넌트 안에서 존재하기 마련이고 그 컴포넌트가 자신의 state를 스스로 변경할 수 있으므로 버그가 존재할 수 있는 범위가 크게 줄어든다.
💡 보일러 플레이트
컴퓨터 프로그래밍에서 보일러플레이트 코드(혹은 그냥 보일러플레이트)는 변화없이 여러 군데에서 반복되는 코드를 말한다. 주로 옛날에 만들어진 언어에서 많이 나타나는데, 프로그래머는 사소한 기능 하나 만드는데도 수 많은 코드를 작성해야 한다.