기존 공식문서와 달리 beta 버전 새 문서에서는 useState() 훅 위주로 state를 설명한다. 사실상 요즘 리액트 개발자들은 90% 이상 이 방식으로 사용하지 싶다.
컴포넌트가 화면에 보이는 것들을 바꿔야 할 경우가 있다 :
이럴 때 컴포넌트는 어떤 정보를 기억 해야 한다. 리액트 컴포넌트에서 이런 정보를 상태 State 라고 한다.
리액트로 처음 개발하다 보면 모든것을 state로 쓰게 된다. 사실 그러면 안됨. 이번 기회에 언제 state를 쓰고 언제 일반 변수를 사용할지 확실히 구분해보자.
// 어떤 버튼의 onClick prop에 handleClick이라는 함수를 넣어뒀다고 치자.
import { sculptureList } from './data.js';
export default function Gallery() {
let index = 0;
function handleClick() {
index = index + 1;
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img
src={sculpture.url}
alt={sculpture.alt}
/>
<p>
{sculpture.description}
</p>
</>
);
}
<h2>
, <img>
, <p>
태그가 바뀌겠지?let은 local variable이기 때문. 지역변수는 리렌더링 될 때 없어진다! 두번째로 렌더링하면 함수를 처음부터 실행시키는 셈인 것이다.
지역변수가 바뀌어도 리렌더링이 안됨! - let이 바뀌어도 내부적으로 바뀐것이지, 변수 하나 바뀌었다고 렌더링이 또 되지는 않음. console.log() 를 찍으면 let값이 바뀌긴 했을 것이나, 리렌더링이 안됐기 때문에 화면은 안바뀐다!
// 이것을 바꿔봅시다
let index = 0;
// 이렇게
const [index, setIndex] = useState(0)
useState 는 인자로 state 의 초기값을 받는다.
→ 0
은 index의 초기값
아래 코드에서 index는 state, setIndex 는
setter 함수다.
setter 함수는 주로 이벤트 핸들러 함수에 넣는다.
function handleNextClick() {
setIndex(index => index + 1)
}
이제 setIndex() 가 실행될 때마다 리렌더링이 일어나고, index는 렌더링 간에 기억된다.
let을 사용하는 것이 더 나을 때도 있나요?
있다.
1. 값이 안바뀔때
값이 안바뀌면 리렌더링을 할 필요가 없기 때문
2. 리렌더링을 할 필요가 없을 때
예를 들어 복잡한 계산을 자주 해야 하면, state가 바뀔 때마다 리렌더링이 일어나게 됨. 차라리 let에 내부 변수를 선언하고, state는 계산이 끝났을 때만 바꿔주는 것이 성능상 좋음.
state는 격리되어 있으며 비공개다.
State는 컴포넌트 인스턴스에 종속되는 private 변수다. 같은 컴포넌트를 두 개 렌더링하면, 같은 이름의 서로 다른 state가 두 개 생김. (함수형 컴포넌트니까 scope 개념이라고 보면 될듯.)
return (
<div>
<Gallery />
<Gallery />
</div>
);
이면 이름은 같지만 서로 영향을 주지 않는 다른 state가 두 개 생길 것임.
부모와 자식 간 : props와 달리, 부모나 자식이 무슨 state를 가졌는지 서로 모름.
각 state를 마음대로 바꿔도 서로 영향을 안줌.
그래서 state를 공유하고 싶다면 props 안에 넣어줘야 함.
다른 컴포넌트 간 : 당연히 서로 모름.
sync 맞추고 싶다면? : 예를 들어 형제나 사촌이라고 치자. 서로 같은 state를 쓰고 싶다면 이렇게 해야 함.
보다시피 상태를 공유하는 작업은 꽤 귀찮은 면이 있음. 그래서 전역상태관리 라이브러리 (redux, recoil) 를 사용하기도 한다.