공식문서를 크게 크게 한 챕터씩 정리하다가
3번째 챕터인 Managing State 부분부터는 한 강의 내용이 슬슬 깊어지는 듯 하여
한 강씩 정리하려고 한다.
Sharing State Between Components
Lifting state up by example
컴포넌트 내부에서 state
를 정의하고 컴포넌트가 내부 state
를 참조하는 JSX
객체를 반환함으로서
상태에 따른 렌더링 로직을 구현해왔다.
import { useState } from 'react';
import './App.css';
export default function App() {
return (
<>
<h1>Title 입니다</h1>
<Panel>나는 Panel 1입니다</Panel>
<br />
<Panel>나는 Panel 2입니다</Panel>
</>
);
}
function Panel({ children }) {
const [isActive, setIsActive] = useState(false);
return (
<div className='container'>
{isActive ? (
<p>{children}</p>
) : (
<button
onClick={() => {
setIsActive(true);
}}
>
show
</button>
)}
</div>
);
}
이렇게 했을 때 Panel 1
이 보일 때에는 Pannel 2
가 보이지 않고 그 반대도 가능하게 하려면 어떻게 할까 ?
function Panel({ children }) {
// Panel 의 state 는 각 컴포넌트 별 고유하게 가지고 있다.
// 이런 local state 는 컴포넌트 내부만 참조 가능하다.
const [isActive, setIsActive] = useState(false);
return (
<div className='container'>
{isActive ? (
<p>{children}</p>
) : (
<button
onClick={() => {
setIsActive(true);
}}
>
show
</button>
)}
</div>
);
}
우선 각 컴포넌트가 서로의 state
를 공유해야 하기 위해서는 각자가 서로 동일한 state
와 setter function
을 받아야 한다.
현재의 컴포넌트는 컴포넌트 내부에서 정의된 state
만 참조하기에 서로의 state
는 공유가 불가능하다.
서로 공유 가능한 state, setter function
은 상위 컴포넌트에서 정의 해준 후
하위 컴포넌트에게 props
로 건내주게 되면 두 컴포넌트는 서로의 상태를 공유 할 수 있게 된다.
import { useState } from 'react';
import './App.css';
export default function App() {
const [activeIndex, setActiveIndex] = useState(0); // 서로가 공유 가능한 state
return (
<>
<h1>Title 입니다</h1>
<Panel
// 현재 활성화 된 index 만 show 되도록 props 건내주기
isActive={activeIndex === 0}
onShow={() => {
// 각 컴포넌트 별 공유하는 setterfunction 을 이용해 state 변경 가능하도록 하기
setActiveIndex(0);
}}
>
나는 Panel 1입니다
</Panel>
<Panel
isActive={activeIndex === 1}
onShow={() => {
setActiveIndex(1);
}}
>
나는 Panel 2입니다
</Panel>
</>
);
}
function Panel({ children, isActive, onShow }) {
return (
<div className='container'>
{isActive ? <p>{children}</p> : <button onClick={onShow}>show</button>}
</div>
);
}
부모 컴포넌트는 하위 컴포넌트에게 서로가 공유 가능한 state
를 props
로 건내주고
하위 컴포넌트들은 부모 컴포넌트의 state
를 변경 할 수 있는 setter function
을 props
로 받아
부모 컴포넌트의 state
를 변경한다.
이렇게 변경된 state
는 re-rendering
과정에서 하위 컴포넌트에게 재전달되며 렌더링을 새롭게 한다.
물론 서로가 공유 가능하게 하기 위해서 공유 불가능하기 전과의
state , setter function
로직이 변경되어야 한다.
Controlled and uncontrolled components
function Panel({ children }) {
const [isActive, setIsActive] = useState(false); // <- local State
return (
<div className='container'>
{isActive ? (
<p>{children}</p>
) : (
<button
onClick={() => {
setIsActive(true);
}}
>
show
</button>
)}
</div>
);
}
이전 예시처럼 컴포넌트 내부에 존재하는 state
들은 부모 컴포넌트나 다른 컴포넌트들이
상태를 변경 할 수 없는 컴포넌트는 uncontrolled component
라고 한다.
function Panel({ children, isActive, onShow }) {
// 상위 컴포넌트로부터 상태에 따른 isActive 변수와
// setter function 을 담은 onShow 를 props 로 받음
return (
<div className='container'>
{isActive ? <p>{children}</p> : <button onClick={onShow}>show</button>}
</div>
);
}
이처럼 부모 컴포넌트로부터 상위 렉시컬 환경의 state, setterFunction
을 props
로 받는 컴포넌트를
Controlled Component
라고 한다.
컴포넌트는 상위 환경의 상태 변화에 따라 컨트롤 할 수 있기 때문이다.
UnControlled Component
는 Controlled Component
에 비해서 사용하기가 쉽고 재활용이 쉽다.
그 이유는 상위 환경이 어떻든과 상관 없이 본인만의 local state
를 가지고 있기 때문에
고려해야 할 것이 없기 때문이다.
Controlled Component
는 UnControlled Component
에 비해서 고려해야 할 것이 많다.
상위 컴포넌트에서 props
로 state
를 건내주어야 하기 때문이다.
하지만 고려할 점이 많다는 것은, 고려만 한다면 더욱 flexible
하게 사용이 가능하다는 것이다.
위 예시에서 보았듯 UnControlled Component
는 다른 컴포넌트와 교류가 안되기 때문에
본인만의 state
에 따른 로직만 처리하여 유연하지 못하다 .
물론 필요한 로직에 따라서는
UnControlled Component
를 사용하는게 맞을 때도 있다.
만약 위 예시에서 서로의 상태와 상관 없이 본인만의 상태에 따라show
를 활성화 할 것이라면
UnControlled Component
로 하는 것이 훨씬 낫다.
본인 내부의isActive state
만 관리하면 되기 때문이다.
컴포넌트는 본인만의 state
에 따라 렌더링이 결정되는 UnControlled Component
,
다른 컴포넌트의 state
에 따라 렌더링이 결정되는 Controlled Component
가 존재한다.
Controlled Component
에 경우에는 상위 컴포넌트에게서 state
를 props
로 전달 받아 사용한다.