State : 컴포넌트의 메모리 - 주요 개념(react docs beta)

hongregii·2023년 2월 26일
0

기존 공식문서와 달리 beta 버전 새 문서에서는 useState() 훅 위주로 state를 설명한다. 사실상 요즘 리액트 개발자들은 90% 이상 이 방식으로 사용하지 싶다.

컴포넌트의 메모리?

컴포넌트가 화면에 보이는 것들을 바꿔야 할 경우가 있다 :

  • 인풋창에 타이핑 했을 때
  • 이미지 목록에서 [다음] 버튼 눌렀을 때 (백엔드랑 연결된 pagination 말고 carousel)
  • [장바구니] 버튼 눌렀을 때

이럴 때 컴포넌트는 어떤 정보를 기억 해야 한다. 리액트 컴포넌트에서 이런 정보를 상태 State 라고 한다.

let / const 로는 부족해!

리액트로 처음 개발하다 보면 모든것을 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>
    </>
  );
}

구현하고 싶은 것 :

  • 버튼을 누를때마다 index값을 바꾸고 싶다.
  • sculptureList에 어떤 정보를 array 형태로 넣어뒀다. 버튼을 누르면 index값이 바뀌니까 let sculpture는 순서대로 바뀔것이다.
  • 그러면 화면에서 <h2>, <img>, <p>태그가 바뀌겠지?

그러나 let으로 index, sculpture를 선언하면 바뀌지 않는다. 왜 why?

  1. let은 local variable이기 때문. 지역변수는 리렌더링 될 때 없어진다! 두번째로 렌더링하면 함수를 처음부터 실행시키는 셈인 것이다.

  2. 지역변수가 바뀌어도 리렌더링이 안됨! - let이 바뀌어도 내부적으로 바뀐것이지, 변수 하나 바뀌었다고 렌더링이 또 되지는 않음. console.log() 를 찍으면 let값이 바뀌긴 했을 것이나, 리렌더링이 안됐기 때문에 화면은 안바뀐다!

그래서 State라는 것은!

  1. 리렌더링이 돼도 state를 초기화 하면 안됨 (메모리처럼)
  2. state가 바뀌면 리렌더링이 돼야 함

useState() 훅은

  1. 렌더링간 유지되는 값 (state 변수) 을 제공
  2. state setter 함수 (state를 설정하는 함수) 제공 → state를 바꿔줌과 동시에 리렌더링함.

이제 useState()를 써보자!

// 이것을 바꿔봅시다
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는 계산이 끝났을 때만 바꿔주는 것이 성능상 좋음.

Isolated, Private

state는 격리되어 있으며 비공개다.

State는 컴포넌트 인스턴스에 종속되는 private 변수다. 같은 컴포넌트를 두 개 렌더링하면, 같은 이름의 서로 다른 state가 두 개 생김. (함수형 컴포넌트니까 scope 개념이라고 보면 될듯.)

 return (
   <div>
    <Gallery />
    <Gallery />
   </div>
  );

이면 이름은 같지만 서로 영향을 주지 않는 다른 state가 두 개 생길 것임.

컴포넌트 밖에선

  • 부모와 자식 간 : props와 달리, 부모나 자식이 무슨 state를 가졌는지 서로 모름.
    각 state를 마음대로 바꿔도 서로 영향을 안줌.
    그래서 state를 공유하고 싶다면 props 안에 넣어줘야 함.

  • 다른 컴포넌트 간 : 당연히 서로 모름.
    sync 맞추고 싶다면? : 예를 들어 형제나 사촌이라고 치자. 서로 같은 state를 쓰고 싶다면 이렇게 해야 함.

    1. 자식 state를 삭제하자.
    2. 가장 가까운 공통 조상에서 state를 선언.
    3. 거기서부터 각각 props로 내려준다.
    4. 주의 : 상태 끌어올리기 를 주의합시다. 자세한 설명은 뒤에서..

보다시피 상태를 공유하는 작업은 꽤 귀찮은 면이 있음. 그래서 전역상태관리 라이브러리 (redux, recoil) 를 사용하기도 한다.

profile
잡식성 누렁이 개발자

0개의 댓글