개발일지

useState 본문

리액트 공식문서 스터디

useState

박수미/ 2024. 5. 17. 21:47

📌 useState란?

컴포넌트에 state변수를 추가할 수 있게 해주는 React 훅입니다.

const [state, setState] = useState(initialState)

 

📌 useState(initialState)

컴포넌트 최상위 레벨에서 useState를 호출하여 state 변수를 선언하기

import { useState } from 'react';

function MyComponent() {
  const [age, setAge] = useState(28);
  const [name, setName] = useState('Taylor');
  const [todos, setTodos] = useState(() => createTodos());
  // ...

배열 구조 분해를 사용하여 [something, setSomething]과 같은 state 변수의 이름을 지정하는 것이 관례입니다.

 

📍 매개변수

  • initialState: 초기에 state를 설정할 값입니다. 값은 모든 데이터 타입이 허용되지만, 함수에 대해서는 특별한 동작이 있습니다. 이 인자는 초기 렌더링 이후에는 무시됩니다.
  • 이 함수는 순수해야 하고 인자를 받지 않아야 하며 반드시 어떤 값을 반환해야 합니다.

📍 반환값

  1. useState는 정확히 두 개의 값을 가진 배열을 반환합니다.현재의 state 첫 번째 렌더링 중에는 전달한 initalState와 일치합니다.
  2. state를 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있는 set함수입니다.

 

📍 주의사항

  • 컴포넌트의 최상위 레벨이나 직접 만든 훅에서만 호출할 수 있습니다. 반복문이나 조건문 안에서는 호출할 수 없습니다. 필요한 경우 새 컴포넌트를 추출하고 state를 그 안으로 옮기세요.

📌 set 함수

useState가 반환하는 set함수를 사용하면 state를 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있습니다. 여기에는 다음 state를 직접 전달하거나, 이전 state로부터 계산하여 다음 state를 도출하는 함수를 전달할 수도 있습니다.

const [name, setName] = useState('Edward');

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

 

📍 매개변수

  • nextState: state가 될 값입니다. 값은 모든 데이터 타입이 허용되지만, 함수에 대해서는 특별한 동작이 있습니다.
  • 함수를 nextState로 전달하면 업데이터 함수로 취급됩니다. 이 함수는 순수해야 하고, 대기 중인 state를 유일한 인수로 사용해야 하며, 다음 state를 반환해야 합니다. React는 업데이터 함수를 대기열에 넣고 컴포넌트를 리렌더링 합니다. 다음 렌더링 중에 React는 대기열에 있는 모든 업데이터를 이전 state에 적용하여 다음 state를 계산합니다.

📍 반환값

set함수는 반환값이 없습니다.

 

📍 주의사항

  • set함수는 다음 렌더링에 대한 state 변수만 업데이트합니다.
  • 사용자가 제공한 새로운 값이 Object.is(두 값이 같은 값인지 결정하는 메서드)에 의해 현재 state와 동일하다고 판단 되면, React는 컴포넌트와 그 자식들을 리렌더링하지 않습니다.
  • React는 state 업데이트를 일괄처리합니다. 모든 이벤트 핸들러가 실행되고 set함수를 호출한 후에 화면을 업데이트합니다.
  • 렌더링 도중 set함수를 호출하는 것은 현재 렌더링 중인 컴포넌트 내에서만 허용됩니다. 해당출력을 버리고 즉시 새로운 state로 다시 렌더링을 시도합니다.

📌 사용방법

1️⃣  컴포넌트에 state 추가하기

컴포넌트 최상위 레벨에서 useState를 호출하여 하나 이상의 state 변수를 선언하세요.

import { useState } from 'react';

function MyComponent() {
  const [age, setAge] = useState(42);
  const [name, setName] = useState('Taylor');
  // ...

useState는 정확히 두 개의 항목이 있는 배열을 반환합니다.

1. 이 state 변수의 현재state(age, name)로, 처음에 제공한 초기 state(42, Taylor) 로 설정됩니다.

2. 상호작용에 반응하여 다른 값으로 변경할 수 있는 set함수(setAge, setName)입니다.

 

화면의 내용을 업데이트하려면 다음 state로 set함수를 호출합니다.

function handleClick() {
  setName('Robin');
}

React는 다음 state를 저장하고 새로운 값으로 컴포넌트를 다시 렌더링한 후 UI를 업데이트합니다.

 

2️⃣  이전 state를 기반으로 state 업데이트하기

age가 42라고 가정합니다. 이 핸들러는 setAge(age + 1)를 세 번 호출합니다:

function handleClick() {
  setAge(age + 1); // setAge(42 + 1)
  setAge(age + 1); // setAge(42 + 1)
  setAge(age + 1); // setAge(42 + 1)
}

그러나 클릭해보면 age는 45가 아니라 43이 됩니다. 이는 set 함수를 호출해도 이미 실행중인 코드에서 age state 변수가 업데이트되지 않기 때문입니다. 따라서 각 setAge(age + 1) 호출은 setAge(43)이 됩니다.

 

이 문제를 해결하려면 다음 state 대신 setAge에 업데이터 함수를 전달할 수 있습니다:

function handleClick() {
  setAge(a => a + 1); // setAge(42 => 43)
  setAge(a => a + 1); // setAge(43 => 44)
  setAge(a => a + 1); // setAge(44 => 45)
}

여기서  a => a + 1은 업데이터 함수입니다. 이 함수는 대기중인 state(a)를 가져와서 다음 state(a + 1)를 계산합니다.

React는 업데이터 함수를 큐(대기열)에 넣습니다. 그러면 다음 렌더링 중에 동일한 순서로 호출합니다.

1. a => a + 1은 대기 중인 state로 42를 받고 다음 state로 43을 반환합니다.

2. a => a + 1은 대기 중인 state로 43을 받고 다음 state로 44를 반환합니다.

3. a => a + 1은 대기 중인 state로 44를 받고 다음 state로 45를 반환합니다.

대기중인 다른 업데이트가 없으므로, React는 결국 45를 현재 state로 저장합니다.

 

3️⃣  객체 및 배열 state 업데이트

state에는 객체와 배열도 넣을 수 있습니다. React에서 state는 읽기전용으로 간주되므로 기존 객체를 변이하지 않고, 교체를 해야합니다. 예를 들어, state에 form객체가 있는 경우 변이하지 마세요:

// 🚩 state 안에 있는 객체를 다음과 같이 변이하지 마세요: 
form.firstName = 'Taylor';

대신 새로운 객체를 생성하여 전체 객체를 교체하세요:

// ✅ 새로운 객체로 state 교체합니다
setForm({
  ...form,
  firstName: 'Taylor'
});

 

4️⃣  초기 state 다시 생성하지 않기

React는 초기 state를 한 번 저장하고 다음 렌더링부터는 이를 무시합니다.

function TodoList() {
  const [todos, setTodos] = useState(createInitialTodos());
  // ...

createInitialTodos()의 결과는 초기 렌더링에만 사용되지만, 여전히 모든 렌더링에서 이 함수를 호출하게 됩니다. 이는 큰 배열을 생성하거나 값비싼 계산을 수행하는 경우 낭비가 될 수 있습니다.

 

이 문제를 해결하려면, 대신 이를 useState에 초기화 함수로 전달하세요:

function TodoList() {
  const [todos, setTodos] = useState(createInitialTodos);
  // ...

함수를 호출한 결과인 createInitialTodos()가 아니라 함수 자체인 createInitialTodos를 전달하고 있다는 것에 주목하세요. 함수를 useState에 전달하면 React는 초기화 중에만 함수를 호출합니다.

 

5️⃣  key로 state 재설정하기

컴포넌트에 다른 key를 전달하여 컴포넌트의 state를 재설정할 수 있습니다. 이 예제에서는 Reset버튼이 version state 변수를 변경하고, 이를 Form에 key로 전달합니다. key가 변경되면  React는 Form컴포넌트(및 그 모든 자식)를 처음부터 다시 생성하므로 state가 초기화됩니다.

export default function App() {
  const [version, setVersion] = useState(0);

  function handleReset() {
    setVersion(version + 1);
  }

  return (
    <>
      <button onClick={handleReset}>Reset</button>
      <Form key={version} />
    </>
  );
}

function Form() {
  const [name, setName] = useState('Taylor');

  return (
    <>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <p>Hello, {name}.</p>
    </>
  );
}

 

 

'리액트 공식문서 스터디' 카테고리의 다른 글

useRef  (0) 2024.05.30
useContext  (0) 2024.05.28
1회차 발표 useState, useReducer  (0) 2024.05.24
useReducer  (0) 2024.05.22
props  (0) 2024.05.13