React.js + Next.js/번역하기

03. useState

진호우 2024. 4. 2. 18:04

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

 

const [state, setState] = useState(initialState)

 

Reference

useState(initialState)

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

import { useState } from 'react';

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

 

[something, setSomething] 형태로 변수 이름을 지정하는 것이 관례이다.

 

Parameters

initialState: 초기에 state를 설정할 값이다. 값은 모든 데이터 타입이 허용되지만, 함수에 대해서는 특별한 동작이 있다. 이 인자는 초기 렌더링 이후에는 무시된다.

함수를 initialState로 전달하면 이를 초기화 함수로 취급한다. 순수함수여야 하고 반드시 어떤 값을 반환해야한다.

 

Returns

useState는 두 개의 값을 가진배열을 반환한다.

1. 현재 state이다. 첫 번째 렌더링중에는 전달한 initialState와 일치한다.

2. state를 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있는 set함수이다.

 

주의사항

useState는 훅이므로 컴포넌트의 최상위 레벨이나 커스텀 훅에서만 호출할 수 있다. 반복문이나 조건문 안에서는 호출할 수 없다. 

Strict Mode에서 React는 의도치 않은 불순물을 찾기 위해 초기화 함수를 두 번 호출한다. 

 

setSomething(nextState)과 같은 set함수

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

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

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

 

Parameters

nextState: state가 될 값. 값은 모든 데이터 타입이 허용되지만, 함수에 대해서는 특별한 동작이 있다.

함수를 nextState로 전달하면 업데이터 함수로 취급된다. 순수함수여야하고, 대기중인 state를 유일한 인수로 사용해야 하며, 다음 state를 반환해야 한다. 

 

Returns

set함수는 반환값이 없다.

 

주의사항

  • set함수는 다음 렌더링에 대한 state변수만 업데이트한다. set함수를 호출한 후에도 state 변수에는 여전히 호출 전 화면에 있던 이전 값이 담겨 있다.
  • 사용자가 제공한 새로운 값이 Object.is에 의해 현재 state와 동일하다고 판정되면, React는 컴포넌트와 그 자식들을 리렌더링하지 않는다. 
  • React는 state업데이트를 일괄처리한다. 모든 이벤트 핸들러가 실행되고 set함수를 호출한 후에 업데이트한다.
  • 렌더링 도중 set함수를 호출하는 것은 현재 렌더링 중인 컴포넌트 내에서만 허용된다. React는 해당 출력을 버리고 즉시 새로운 state로 다시 렌더링을 시도한다.
  • Strict Mode에서 React는 의도치않은 불순물을 찾기 위해 업데이터 함수를 두 번 호출한다. 개발 환경 전용으로 동작하며 호출 중 하나의 결과는 무시한다.

Usage

컴포넌트에 state 추가하기

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

import { useState } from 'react';

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

 

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

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

 

  1. 이 state 변수의 현재 state로, 청므에 제공한 초기 state로 설정된다.
  2. 상호작용에 반응하여 다른 값으로 변경할 수 있는 set함수이다.

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

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

 

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

function handleClick() {
  setName('Robin');
  console.log(name); // 아직 이전 상태가 호출된다
}

 

 

이전 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에 업데이터 함수를 전달할 수 있다.

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를 가져와서 다음 state를 계산한다.

React는 업데이터 함수를 큐에 넣는다. 그러면 다음 렌더링 중에 동일한 순서로 호출한다.

대기중인 업데이트가 없으므로 React는 45를 현재 state로 저장한다.

 

aged의 a와 같이 state 변수 이름의 첫 글자로 지정하는 것이 일반적이다. 그러나 prevAge같이 명확한 다른 이름으로 지정해도 된다.

 

객체 및 배열 state 업데이트

state에는 객체와 배열도 넣을 수 있다. React에서 state는 읽기 전용으로 간주되므로 기존 객체를 변경하지 않고 교체를 해야한다. 

// 🚩 state 안에 있는 객체를 다음과 같이 변경 금지
form.firstName = 'Taylor';

 

새로운 객체를 생성하여 전체 객체를 교체하자

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

 

초기 state 다시 생성하지 않기

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

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

 

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

이 문제를 해결하려면 useState에 초기화 함수로 전달하자.

 

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

 

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

 

key로 state 재설정하기

목록을 렌더링할 때 key 속성을 자주 접하게 된다.

컴포넌트에 다른 key를 전달하여 컴포넌트의 state를 재설정 할 수 있다. 

 

이전 렌더링에서 얻은 정보 저장하기

보통은 이벤트 핸들러에서 state를 업데이트 한다. 하지만 렌더리에 대한 응답으로 state를 조정해야 하는 경우도 있다. 예를 들어 props가 변경될 때 state 변수를 변경하고 싶을 수 있다.

 

필요한 값을 현재 props나 다른 state에서 모두 계산할 수 있는 경우 중복되는 state를 모두 제거하자. 너무 자주 재계산하는 것이 걱정도니다면 useMomo를 이용하자.

 

전체 컴포넌트 트리의 state를 재설정하려면 컴포넌트에 다른 key를 전달하자.

 

가능하다면 이벤트 핸들러의 모든 관련 state를 업데이트하자.

 

 

'React.js + Next.js > 번역하기' 카테고리의 다른 글

02. useMomo  (0) 2024.01.13
01. memo  (0) 2023.12.04