두 컴포넌트의 state가 항상 함께 변경되기를 원한다면, 두 컴포넌트에서 state를 제거하고 가장 가까운 공통 부모로 이동한 다음 props를 통해 전달하면 된다.
Lifting state up by example(예제로 알아보는 state 끌어올리기)
import { useState } from 'react';
function Panel({ title, children }) {
const [isActive, setIsActive] = useState(false);
return (
<section className="panel">
<h3>{title}</h3>
{isActive ? (
<p>{children}</p>
) : (
<button onClick={() => setIsActive(true)}>
Show
</button>
)}
</section>
);
}
export default function Accordion() {
return (
<>
<h2>Almaty, Kazakhstan</h2>
<Panel title="About">
With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
</Panel>
<Panel title="Etymology">
The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
</Panel>
</>
);
}
위 예제에서, 부모 컴포넌트인 Accordion 컴포넌트가 두 개의 Panel 컴포넌트를 렌더링 하고 한 패널의 버튼을 눌러도 다른 패널에 영향을 주지 않고 독립적으로 동작한다.
하지만, 만약 패널이 하나만 열린 상태를 유지하려고 할때, 두 번째 패널을 열기 위해서는 첫 번째 패널을 닫아야 한다. 이때 부모 컴포넌트로 state를 끌어올려야 한다.
1. 자식 컴포넌트에서 state 제거
2. 공통 부모 컴포넌트에 하드 코딩된 데이터를 전달
3. 공통 부모 컴포넌트에 state를 추가하고 이벤트 핸들러와 함께 전달
Step 1 : Remove state from the child components(자식 컴포넌트에서 state 제거)
Panel 컴포넌트에서 state 정의를 제거하고, 부모 컴포넌트가 isActive를 Panel에 prop으로 대신 전달하게 한다.
Step 2 : Pass hardcoded data from the common parent(공통 부모에 하드 코딩된 데이터 전달하기)
state를 끌어올릴려면 조정하려는 두 자식 컴포넌트의 가장 가까운 공통 부모 컴포넌트를 찾아야하고, 위 예제에서는 Accordion 컴포넌트가 가장 가까운 공통 부모 컴포넌트이다.
Step 3 : Add state to the common parent(공통 부모에 state 추가)
위 예제에서 활성화된 패널을 추적하기 위해 Panel의 인덱스를 나타내는 숫자를 state 변수로 사용할 수 있다.
import { useState } from 'react';
export default function Accordion() {
const [activeIndex, setActiveIndex] = useState(0);
return (
<>
<h2>Almaty, Kazakhstan</h2>
<Panel
title="About"
isActive={activeIndex === 0}
onShow={() => setActiveIndex(0)}
>
With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
</Panel>
<Panel
title="Etymology"
isActive={activeIndex === 1}
onShow={() => setActiveIndex(1)}
>
The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
</Panel>
</>
);
}
function Panel({
title,
children,
isActive,
onShow
}) {
return (
<section className="panel">
<h3>{title}</h3>
{isActive ? (
<p>{children}</p>
) : (
<button onClick={onShow}>
Show
</button>
)}
</section>
);
}
위 코드를 보면, 각 Panel에서 Show 버튼을 클릭하면 Accordian으로부터 전달받은 이벤트 핸들러를 통해 활성화된 인덱스를 변경한다.
* 제어 컴포넌트, 비제어 컴포넌트
비제어 컴포넌트 : 일부 로컬 state를 가진 컴포넌트로, 구성이 덜 필요하기 때문에 상위 컴포넌트 내에서 사용하기가 쉽지만 함께 통합하려는 경우 유연성이 떨어진다.
제어 컴포넌트 : 컴포넌트의 중요한 정보가 자체 로컬 state가 아닌 props에 의해 구동되는 컴포넌트이다.
A single source of truth for each state(각 state의 단일 진실 공급원(SSOT))
React 앱에서 많은 컴포넌트들은 고유한 state를 가지고 있다. 각 고유한 state들에 대해 해당 state를 "소유"하는 컴포넌트를 선택하게 되는데, 이 원칙은 단일 진실 공급원이라고도 한다.
이는 모든 state가 한 곳에 있다는 뜻이 아닌, 각 state마다 해당 정보를 소유하는 특정 컴포넌트가 있다는 뜻이며, 컴포넌트 간에 공유하는 state를 복제하는 대신 공통으로 공유하는 부모로 끌어올려서 필요한 자식에게 전달하는 것을 말한다.
* 참고 : React 공식문서(https://react-ko.dev/learn)
'이것저것 스터디📚 > React - 공식 문서' 카테고리의 다른 글
React 공식문서 -Extracting State Logic into a Reducer(State 로직을 Reducer로 추출하기) (0) | 2023.08.09 |
---|---|
React 공식문서 -Preserving and Resetting State(state 보존 및 재설정) (0) | 2023.08.03 |
React 공식문서 -Choosing the State Structure(State 구조 선택) (0) | 2023.08.02 |
React 공식문서 - Reacting to Input with State(state로 입력에 반응하기) (0) | 2023.08.02 |
React 공식문서 -Updating Arrays in State(배열 state 업데이트) (0) | 2023.07.26 |