일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 내배캠 프로젝트
- 파이썬 반복문
- 파이썬 for in
- 리액트 프로젝트
- 코딩테스트
- 타입스크립트 리액트
- 파이썬 replace
- 내일배움캠프 최종 프로젝트
- 파이썬 for
- 파이썬 slice
- REACT
- 자바스크립트
- 타입스크립트 props
- Next 팀 프로젝트
- 리액트 공식문서
- 한글 공부 사이트
- 내일배움캠프
- JavaScript
- 내일배움캠프 프로젝트
- 프로그래머스
- React Hooks
- 파이썬 enumerate
- 리액트 훅
- typeScript
- useEffect
- 파이썬 딕셔너리
- tanstack query
- 리액트
- 타입스크립트
- useState
- Today
- Total
sohyeon kim
[React] 리액트 공식문서 정리 3(2) : State 관리하기 - 컴포넌트 간 state 공유, 상태 보존 및 초기화, key 활용 본문
[React] 리액트 공식문서 정리 3(2) : State 관리하기 - 컴포넌트 간 state 공유, 상태 보존 및 초기화, key 활용
aotoyae 2024. 12. 6. 14:17
💡 리액트 공식문서 정리 : State 관리하기 - 컴포넌트 간 State 공유하기, State 를 보존하고 초기화하기
3. 컴포넌트 간 State 공유하기 : state 를 부모 컴포넌트로 끌어올려 props 로 내려준다.
두 컴포넌트의 state 가 항상 함께 변경되기를 원할 때
➡️ 각 컴포넌트에서 state 를 제거하고 가장 가까운 공통 부모 컴포넌트로 옮겨 props 로 전달한다.
아래에서 각 패널은 독립적인 state 를 가지고 있어 show 버튼을 눌러도 다른 패널에 영향을 미치지 않는다.
function Panel({ title, children }) { // 비제어 컴포넌트. 부모로무터 제어되지 않는다.
const [isActive, setIsActive] = useState(false);
이제 한 번에 하나의 패널만 열리도록 변경해 보자.
부모 컴포넌트로 state 를 옮기고 Panel 에는 props 를 내려준다.
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 //..
</Panel>
<Panel
title="Etymology"
isActive={activeIndex === 1}
onShow={() => setActiveIndex(1)}
>
The name comes from //..
</Panel>
</>
);
}
function Panel({ title, children, isActive, onShow }){ // 제어 컴포넌트.
//..
}
컴포넌트 간의 공유된 state 도 중복되지 않게 그들의 공통 부모로 끌어올리고 필요한 자식에게 전달하자.
작업이 진행되면서 애플리케이션은 계속 변한다. 각 state가 어디에 '생존'해야 할지 고민하는 동안 state를 아래로 이동하거나 다시 올리는 것은 흔히 있는 일다. 이건 모두 과정의 일부이다!
4. State 를 보존하고 초기화하기 : React 는 언제, 어떻게 state 를 컨트롤하는가?
React 는 UI 트리에서의 위치를 통해 각 State 가 어떤 컴포넌트에 속하는지 추척한다.
State 는 렌더 트리의 위치에 연결된다.
- React 는 UI 안에 있는 컴포넌트 구조로 렌더 트리를 만든다.
- UI 트리에 있는 컴포넌트의 위치를 이용해 React 가 가지고 있는 각 State 를 알맞은 컴포넌트와 연결한다.
- 컴포넌트에 state 를 줄 때 state 가 컴포넌트 안에 '살고' 있다고 생각할 수 있다.
하지만 사실 state 는 React 안에 있다.
- 컴포넌트에 state 를 줄 때 state 가 컴포넌트 안에 '살고' 있다고 생각할 수 있다.
여기 동일한 JSX 태그가 다른 두 군데에서 렌더링되고 있다.
이 둘은 각각 트리에서 자기 고유의 위치에 렌더링되어 있으므로 분리되어있는 카운터다.
카운터를 클릭해도 다른 컴포넌트에 영향일 끼지지 않는다.
❗️ React 는 트리의 동일한 컴포넌트를 동일한 위치에 렌더링하는 동안 상태를 유지한다.
두 번째 카운터가 렌더링되지 않았다가 다시 나타나면 state 가 초기화된 것을 확인할 수 있다.
이는 React 가 컴포넌트를 제거할 때 그 state 도 같이 제거하기 때문이다.
❗️ 그러므로 같은 자리의 같은 컴포넌트는 state 를 보존한다.
여기 서로 다른 두 <Counter /> 태그를 보자.
체크 박스를 선택하거나 해제할 때 카운터 state 는 초기화되지 않는다.
isFancy 가 true 이든 false 이든 <Counter /> 는 같은 자리에 있기 때문. (root App 컴포넌트가 반환한 div의 첫 번째 자식으로)
첫 번째 자리의 같은 컴포넌트이기 때문에 React 의 관점에선 같은 카운터이다. (React 는 UI 트리에서의 위치에 관심이 있다.)
같은 위치의 다른 컴포넌트는 state 를 초기화한다.
아래처럼 다른 태그인 p 로 교체되거나 같은 카운터라도 감싸고 있는 태그가 달라지면
React 는 다른 컴포넌트로 인식해 컴포넌트와 state 가 제거된다.
🙋♂️ 리렌더링 시 state 를 유지하고 싶다면, 트리 구조가 '같아야'한다.
같은 위치에서 state 초기화하기
기본적으로 React 는 컴포넌트가 같은 위치를 유지하면 state 를 유지한다.
하지만 컴포넌트의 state 를 초기화하고 싶다면?
1️⃣ 컴포넌트를 다른 위치에 렌더링하기
return (
<div>
{isPlayerA &&
<Counter person="Taylor" />
}
{!isPlayerA &&
<Counter person="Sarah" />
}
처음엔 isPlayerA 가 true 이므로, 첫 번째 자리에 Counter 가 있고 두 번째 자리는 비어있다.
'Next player' 를 클릭하면 첫 번째 자리가 비워지고 두 번째 자리에 Counter 가 온다.
(이 방법은 같은 자리에 적은 수의 독립된 컴포넌트만을 가지고 있을 때 편리하다. 이 예시에선 두 개뿐이기에 JSX 에서 각각 렌더링하기 번거롭지 않았다.)
2️⃣ key 를 이용해 state 초기화하기
배열을 렌더링할 때 key 를 사용했을 것이다. 하지만 key 는 배열을 위한 것만은 아니다!
React 가 컴포넌트를 구별할 수 있도록 key 를 사용할 수도 있다.
기본적으로 React 는 컴포넌트를 구별하기 위해 부모 안에서의 순서('첫 번째 카운터', '두 번째 카운터')를 이용한다.
하지만 key 를 명시하면 React 는 부모 내에서의 순서 대신 key 자체를 위치의 일부로 사용한다.
위치가 같아도 React 관점에선 다른 카운터인 것!
예를 들면 Taylor 의 카운터처럼. 이렇게 하면 트리 어디에서 나타나는 React 는 Taylor 의 카운터라는 것을 알 수 있다.
return (
<div>
{isPlayerA ? (
<Counter key="Taylor" person="Taylor" />
) : (
<Counter key="Sarah" person="Sarah" />
)}
key 가 다르기 때문에 두 <Counter /> 는 JSX 에서 같은 위치에 나타나지만, state 를 공유하지는 않는다.
❗️ key 는 전역적으로 유일하지 않다. key 는 오직 부모 안에서만 자리를 명시한다.
key 를 이용해 폼 초기화하기
key 로 state 를 초기화하는 것은 특히 폼을 다룰 때 유용하다.
다음 채팅 앱에서 <Chat> 컴포넌트는 문자열 입력 state 를 가지고 있다.
현재는 입력란에 타이핑을 하고 다른 수신자를 선택해도 <Chat> 이 트리의 같은 곳에서 렌더링되기에 입력값이 유지된다.
이것을 고치기 위해 key 를 추가할 수 있다.
<Chat key={to.id} contact={to} />
이제 다른 수신자를 선택하면 <Chat> 컴포넌트가 그 트리에 잇는 모든 state 를 포함해 처음부터 다시 생성된다.
React 는 DOM 엘리먼트도 다시 사용하는 대신 새로 만들 것이다.
하지만 제거된 컴포넌트의 state 를 보존하고 싶다면?
실제 채팅 앱에선 이전의 수신자를 선택햇을 대 입력했던 값이 복구되는 것을 원할 것이다.
보이지 않는 컴포넌트의 state 를 '살아 있게' 하는 몇 가지 방법이 있다.
- 현재 채팅만 렌더링하는 대신 모든 채팅을 렌더링하고 CSS 로 안보이게 설정
- 채팅은 트리에서 사라지지 않을 것이므로 그들의 state 는 유지된다.
- 이 방법은 간단한 UI 에서 잘 작동하지만, 숨겨진 트리가 크고 많은 DOM 노드를 가지고 있다면 매우 느려질 것
- state 를 상위로 올려 각 수신자의 임시 메세지를 부모 컴포넌트에 유지
- 부모가 정보를 가지고 있기에 자식 컴포넌트가 제거되어도 상관이 없다. 가장 일반적인 해법
- React state 이외의 다른 저장소 이용(예시로, 실수로 페이지를 닫아도 메세지를 유지하고 싶은 경우)
- localStorage 에 메세지를 저장하고 이를 이용해 Chat 컴포넌트를 초기화
이 중 어떤 방법을 선택하더라도 Alice 와의 채팅은 Bob 과의 채팅 과 개념상 구별되기 때문에
현재 수신자를 기반으로 <Chat> 트리에 key 를 주는 것은 타당하다.
🔗 https://ko.react.dev/learn/sharing-state-between-components