Frontend/React

React Study - 8. Hooks (1) - useState

rachel_13 2023. 5. 16. 07:05

함수형 컴포넌트에서는 앞서 공부한 라이프 사이클 메서드를 사용할 수 없다.

React v16.8부터는 함수형 컴포넌트에서도 클래스형 컴포넌트의 라이프 사이클 메서드와 유사한 기능을 할 수 있는 기능들을 제공한다.

 

1. useState

가장 기본적인 hook. 가변적인 상태를 지닐 수 있다.

 

(1) 사용 예

  • state를 컴포넌트에 추가할 때
  • 이전 state에서 상태값 업데이트가 필요할 때
  • 배열이나 객체 state를 업데이트 할 때
  • 초기값을 재생성하는 것을 막고 싶을 때
  • key와 함께 state를 초기화 시키고 싶을 때
  • 이전 렌더링 정보를 저장하고 싶을 때

 

(2) useState(initialState)

컴포넌트 최상단에 state 변수를 할당하며, 컨벤션은 일반적으로 [이름, set이름] 이런식으로 배열 구조 분해를 사용한다.

import {useState} from 'react';

const MyComponent = () => {
    const [something, setSomething] = useState('Hello');
}

 

[파라미터 | 매개변수]

- initialState : 상태를 초기에 지정할 값이다.

- 모든 유형이 값이 될 수 있지만 함수에는 특별한 동작이 있다.이 인수는 초기 렌더링 후 무시된다.

- 만약 함수를 인수로 넣게 될 경우, 이 함수는 init 함수로서의 역할을 한다. 이 때 이 함수는 순수함수여야 하고, 매개변수가 없고 반환 값이 반드시 있어야 하는 특징이 있다.

- React는 컴포넌트를 초기화 하고 싶을 때 이 init 함수를 호출하고 반환 값을 초기 상태로 지정한다.

 

[반환 | return]

useState는 2가지 value를 리턴한다.

- 1) 현재의 state 값을 리턴하는데, 최초 렌더링 시에는 초기에 선언한 initialState 값이 리턴된다.

- 2) set 함수를 리턴한다. 이 함수는 값이 변경될 때, state를 업데이트 시키고 재렌더링을 트리거한다.

 

[유의사항]

- useState도 Hook 의 일종이기 때문에, 컴포넌트의 최상단에서 선언해주어야 한다. 루프 안에서 혹은 조건문 안에서 선언하면 안되고, 만약 이런 것들이 필요한 상황이라면 새로운 컴포넌트를 만들어서 state를 넘겨주는 방식을 사용해야 한다.

- Strict Mode에서 리액트는 초기(initializer) 함수가 순수함수가 아닌 경우를 감지하기 위해 initializer Function을 두 번 호출 할 것이다. 이는 개발 환경에서만 동작하며, 프로덕션에는 영향을 미치지 않는다. 초기 함수가 순수한 경우(순수해야 함) 동작에 영향을 주지 않아야 한다. 호출 중 하나의 결과는 무시된다.

 

 

2. set 함수 (setSomething) (nextState)

set에서 반환한 함수를 사용하면 상태(state)를 다른 값으로 업데이트하고 다시 렌더링을 트리거할 수 있다.

setState 함수를 사용하여 다음 상태를 직접 전달하거나, 이전 상태에서 계산하는 함수를 전달할 수 있다.

const [name, setName] = useState('Rachel');
const [age, setAge] = useState(20);

function handleClick() {
  setName('Taylor');
  setAge(a => a + 1);
  // ...

 

[파라미터 | 매개변수]

- nextState : 업데이트 함수. 순수함수여야 함. 변경되어야 할 상태값만 인자로 가져올 수 있다. 그리고 다음 state값(변경된 혹은 업데이트 된)을 반환해야 한다. React는 이 setState 함수(업데이트 함수)를 큐에 넣어두었다가 컴포넌트를 재렌더링 시킨다.

다음 렌더링 동안 React는 이전 상태와 비교하여 큐(대기열)에 걸린 업데이트를 적용하여 다음 상태값을 계산한다.

 

[반환 | returns]

setState 함수는 반환값이 없다.

 

[유의사항]

1. setState 함수는 다음 렌더링을 위한 상태 값만 업데이트 한다.

- setState 함수가 호출 된 후에 state 값을 읽으면, 호출 전 화면에 있던 이전 값(old value)이 보일 것이다.

2. 새롭게 업데이트 된 값이 현재 state와 같다면, 리액트는 해당 컴포넌트와 그 자식 컴포넌트들의 재 렌더링을 건너뛴다.

3. React는 상태 업데이트를 일괄 처리한다.

- 모든 이벤트 핸들러가 실행되고 setState 함수가 호출되고 난 후 화면을 업데이트한다. 이는 단일 이벤트에 여러 렌더링이 발생하는 것을 막을 수 있다. 물론, DOM에 엑세스 하기 위해 React가 화면을 일찍 업데이트 하도록 강제해야 하는 경우도 있다.

4. 렌더링이 되는 동안 set 함수를 호출하는 것은 현재 렌더링되는 컴포넌트 내에서만 허용된다.

- React는 현재 렌더링하고 있던 ouput을 버리고 즉시, 새로운 state 값을 반영한 컴포넌트를 그릴 것이다.

(이 패턴은 거의 사용할 일은 드물지만, 이전 렌더링의 정보를 저장할 때 유용하다)

5. Strict Mode에서 업데이트 기능을 두 번 호출한다.

 

 

3. 사용법

1) Basic Examples

 

2) 이전 State에서 상태값 업데이트 하기 (prevState Updating)

  • 업데이터*를 사용하는 것이 항상 좋을까?
    : setAge(a+1) 대신 setAge(a => a+1)로 사용하라는 것처럼 느껴질 수 있다. 이 방법은 필수로 요구되는 방법이 아니며, 대부분의 경우에서 두 접근 방식에 대해 차이가 없다. React는 항상 유저의 의도된 action(예를 들면 클릭같은..)에 반응하기 때문에 다음 클릭 전에 state 변수가 업데이트되도록 항상 확인한다 . age즉, 클릭 핸들러가 이벤트 핸들러 시작 부분에서 "stale 상태"를 볼 위험이 거의 없다 .
  • 그러나, 동일 이벤트 내에 여러 업데이트가 발생할 경우에는 업데이터 함수가 도움이 될 수 있다.
  • * 업데이터 : Updater function / pending 된 state를 가져와서 다음 state를 계산하는 함수.React에서는 이 업데이터 함수를 큐(대기열)에 올리고, 다음 렌더링 동안 순차적으로 호출한다.
  • 예시)
    - Updater Function을 사용하는 경우
import { useState } from 'react';

export default function Counter() {
  const [age, setAge] = useState(42);

  function increment() {
    setAge(a => a + 1);
  }

  return (
    <>
      <h1>Your age: {age}</h1>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <button onClick={() => {
        increment();
      }}>+1</button>
    </>
  );
}

      - 사용하지 않는 경우

import { useState } from 'react';

export default function Counter() {
  const [age, setAge] = useState(42);

  function increment() {
    setAge(age + 1);
  }

  return (
    <>
      <h1>Your age: {age}</h1>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <button onClick={() => {
        increment();
      }}>+1</button>
    </>
  );
}

     -> 이 경우는 항상 +1만큼 밖에 업데이트가 되지 않는다. 그 이유는 이미 실행 중인 코드에서 state 변수는 set 함수를 호출한다고
         업데이트되지 않기 때문이다.

 

 

3) Object 형 또는 Array형인 State 값 업데이트하기

npm i immer
npm i use-immer

4) 초기 값(initial state) 재 생성 피하기