useState는 컴포넌트에 state 변수를 추가할 수 있는 React Hook이다.
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());
// ...
배열 구조 분해를 사용하여 [somthing, setSomthing]과 같은 state 변수의 이름을 지정하는 것이 규칙.
매개변수
- initialState : state의 초기 설정값. 어떤 유형의 값이든 지정할 수 있다.
- 함수를 initialState로 전달하면 이를 초기화 함수로 취급한다. React는 컴포넌트를 초기화할 때 초기화 함수를 호출하고, 그 반환값을 초기 state로 저장한다.
반환값
useState는 정확히 두 개의 값을 가진 배열을 반환한다.
1. 현재 state. 첫 번째 렌더링 중에는 initialState와 일치
2. state를 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있는 set함수
주의사항
- useState는 Hook이므로 컴포넌트의 최상위 레벨이나 직접만든 Hook에서만 호출할 수 있다. 반복문이나 조건문 안에서는 호출 x
- Strict Mode에서는 초기화 함수를 두 번 호출한다. 이는 개발 환경 전용 동작이며 프로덕션 환경에서는 영향 x
setSomething(nextstate)와 같은 set 함수
useState가 반환하는 set 함수를 사용하면 state를 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있다.
const [name, setName] = useState('Edward');
function handleClick() {
setName('Taylor');
setAge(a => a + 1);
// ...
파라미터
- nextState : state가 될 값이다. 값은 모든 데이터 타입을 허용되지만, 함수에 대해서는 특별한 동작이 있다.
- 함수를 nextState로 전달하면 업데이터 함수로 취급한다. 대기중인 state를 유일한 인수로 사용해야 하며, 다음 state를 반환해야 한다.
set 함수는 반환값이 없다.
주의사항
- set함수는 다음 렌더링에 대한 state 변수만 업데이트 한다.
- 사용자가 제공한 새로운 값이 현재 state와 동일하다면 React는 리렌더링하지 않는다.
- React는 state 업데이트를 batch 한다.
- 렌더링 도중 set 함수를 호출하는 것은 현재 렌더링 중인 컴포넌트 내에서만 허용된다.
- Strict Mode 에서 React는 의도치 않은 불순물을 찾기 위해 업데이터 함수를 두 번 호출한다.
사용법
컴포넌트에 state 추가하기
컴포넌트의 최상위 레벨에서 useState를 호출하여 하나 이상의 state변수를 선언.
import { useState } from 'react';
function MyComponent() {
const [age, setAge] = useState(42);
const [name, setName] = useState('Taylor');
// ...
배열 구조 분해를 사용해 [state, setState]와 같은 state 변수의 이름을 지정하는 것이 관례이다.
화면의 내용을 업데이트 하려면
function handleClick() {
setName('Robin');
}
setState를 사용해 변경해준다.
주의할점으로는
function handleClick() {
setName('Robin');
console.log(name); // 아직 "Taylor"입니다!
}
이처럼 이미 실행 중인 코드의 현재 state는 변경되지 않는다.
이전 state를 기반으로 업데이트하기
age가 42라고 가정하고 보면
function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}
이렇게 하면 3번 해서 45가 나올것 같지만 43이 나오게 된다.
이미 실행중인 코드에서 state가 업데이트되지 않기 때문이다.
이 문제를 해결하려면 업데이터 함수를 전달해야 한다.
function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}
대기중인 state를 가져와서 계산을 하게 되는 것이다.
웬만하면 업데이터 함수를 사용해주는게 좋다고 한다.
객체 및 배열 state 업데이트 하기
state에는 객체와 배열도 넣을 수 있다.
// 🚩 state 안에 있는 객체를 다음과 같이 변경하지 마세요.
form.firstName = 'Taylor';
대신 새로운 객체를 생성해 전체 객체를 교체해주면 된다.
// ✅ 새로운 객체로 state를 교체합니다.
setForm({
...form,
firstName: 'Taylor'
});
초기 state 다시 생성하지 않기
React는 초기 stste를 한 번 저장하고 다음 렌더링 부터는 이를 무시한다.
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...
createInitialTodos()의 결과는 초기 렌더링에 사용되지만, 이는 큰 배열을 생성하거나 값비싼 계산을 수행하느 경우 낭비일 수 있다.
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...
초기화 함수로 전달해주면 된다.
key로 state 초기화
목록을 렌더링할 때 key 속성을 자주 접하게 되는데 이 key 속성은 다른 용도로도 사용 된다.
컴포넌트에 다른 key를 전달하여 컴포넌트의 state를 초기화 할 수 있다.
import { useState } from 'react';
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>
</>
);
}
만약 리렌더링 횟수가 너무 많다면?
// 🚩 잘못된 방법: 렌더링 동안 핸들러 요청
return <button onClick={handleClick()}>Click me</button>
// ✅ 올바른 방법: 이벤트 핸들러로 전달
return <button onClick={handleClick}>Click me</button>
// ✅ 올바른 방법: 인라인 함수로 전달
return <button onClick={(e) => handleClick(e)}>Click me</button>
state의 값으로 함수를 설정하려면?
const [fn, setFn] = useState(someFunction);
function handleClick() {
setFn(someOtherFunction);
}
이런식으로 하게 되면 someOtherFunction을 업데이터 함수로 여기고 그 결과를 저장하려고 시도하게 된다.
저 함수를 저장하길 원한다면 ()=>를 앞에 넣어줘야 한다.
const [fn, setFn] = useState(() => someFunction);
function handleClick() {
setFn(() => someOtherFunction);
}'리액트 공식문서 읽어보기' 카테고리의 다른 글
| useCallback (0) | 2024.03.02 |
|---|---|
| <Suspense> (1) | 2024.02.25 |
| lazy (0) | 2024.02.25 |
| useRef (0) | 2024.02.23 |
| useMemo (0) | 2024.02.22 |