| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- TypeScript
- 개발 공부
- useMemo
- 프론트엔드
- next.js
- 프로그래머스
- 리액트
- 입문
- JavaScript
- 알고리즘
- 개발자취업부트캠프
- 이벤트
- 모던 자바스크립트 딥 다이브
- 패스트캠퍼스
- 공식문서
- 자료구조
- 비전공자
- 자바스크립트
- CSS
- react
- 모던 딥 다이브 자바스크립트
- useRef
- 내일배움카드
- 메가바이트스쿨
- MegabyteSchool
- styled-components
- GIT
- 코딩테스트
- Github
- 국비지원교육
- Today
- Total
개발 기록 남기기✍️
[React] React Hooks, useState란 무엇인가 본문
useState는 너무 기본적인 개념이라서 뭐 정리할 필요 있겠어? 했는데
useState는 async 방식으로 동작한다는 등 몰랐던 개념들이 많아서...
오만했던 내 모습을 반성하고 useState를 알아보자.🏃♀️
⚛️ React Hooks
리액트의 Hook은 함수형 컴포넌트에서 React state와 생명주기 기능을 “연동(hook into)“할 수 있게 해주는 함수이다.
리액트에 함수형 컴포넌트가 도입되면서, 리액트는 함수형 컴포넌트가 어떤 값(상태)을 유지할 수 있도록 "캐시"를 만들었다.
이 캐시를 이용하고자 만든 여러 개의 API를 Reack Hook 함수라고 부른다.
Hook은 함수형 컴포넌트 안에서만 동작하며, class 없이 React를 사용할 수 있게 해준다.
🧐 React Hook을 도입한 목적
- 컴포넌트에서 상태 관련 로직을 사용할 때 Hook 이전에 재사용 가능한 로직을 사용하기 위해서는, render props나 고차 컴포넌트와 같은 패턴을 사용했는데, 이런 패턴은 코드의 추적을 어렵게 만들어 오류가 발생하기 쉽고 유지보수가 어렵다.
✅ Hook을 활용하면 상태 관련 로직을 추상화해 독립적인 테스트와 재사용이 가능해 레이어 변화 없이 재사용할 수 있다. - 기존의 라이프사이클 메서드 기반이 아닌 로직 기반으로 나눌 수 있어서 컴포넌트를 함수 단위로 잘게 쪼갤 수 있다.
(라이프사이클 메서드에는 관련 없는 로직이 자주 섞여 들어가는데, 이로 인해 버그가 쉽게 발생하고, 무결성을 쉽게 해친다.)
✨ Hook 사용 규칙
- 컴포넌트의 최상위에서만 Hook을 호출해야 한다. ( 반복문, 조건문, 중첩된 함수 내에서 Hook을 실행하면 안된다. )
이 규칙을 따르면 컴포넌트가 렌더링될 때마다 항상 동일한 순서로 Hook이 호출되는 것이 보장된다. - 리액트 함수 컴포넌트에서만 Hook을 호출해야 하고, 일반 JS 함수에서는 Hook을 호출해서는 안된다.
- Hook의 콜백 함수로 비동기 함수를 사용할 수 없다.
⚛️ useState
🤯 Class형 컴포넌트의 상태 관리
아래 예제 코드는 사용자의 이름과 이메일을 입력받기 위한 React 컴포넌트이다.
클래스 컴포넌트의 this.state 필드에 이름과 이메일 값을 저장해두고 render() 내에서 this.state를 구조분해 할당하여 state를 사용한다.
사용자가 이 값을 변경할 때마다 this.setState를 통해 값이 갱신되고 다시 화면에 반영이 된다.
✅ useState로 상태 관리하기
useState() 함수는 두 개의 요소가 담긴 배열을 리턴한다.
- state(첫 번째 요소) : 상태 값을 저장할 변수
- setState(두 번째 요소) : 해당 상태 값을 갱신할 때 사용할 수 있는 함수. 동시에 리렌더링의 트리거 역할을 한다.
- initialState : useState의 매개변수로서, 최초 렌더링 시 들어갈 값(any type)을 넣어준다.
const [count, setCount] = useState(0);
↑ ↑ ↑
state setFunc initialState
✨ setState
✅ setState의 매개변수로는 함수를 포함한 모든 타입의 값(any type)을 받을수 있다.
(하지만 매개변수로 함수로 받으려면 해당 함수는 pure한 함수여야 한다.)
setState 함수는 새 state 값을 받아서 컴포넌트 리렌더링을 큐(queue)에 등록한다.
✅ setSate는 다음 렌더링 때 state를 업데이트 한다.
모든 setState 함수는 비동기(asynchronous) 방식으로 동작한다.
그렇기 때문에 setState 함수를 실행한다고 해서 state가 바로 바뀌지는 않는다.
state의 값이 변경되지 않으면 리액트는 리렌더링하지 않는다.
✅ value 업데이트를 일괄처리(batch) 한다.
모든 이벤트 핸들러와 그 set function이 호출되고 난 후 화면을 업데이트 한다.
그래서 하나의 이벤트가 일어나는 동안 여러 번 리렌더링 되는 것을 막을 수 있다.
✅ setValue를 리렌더링 동안 호출하는 것은 현재 렌더링되는 컴포넌트 내에서만 가능하다.
원래 리턴값을 급취소하고, 새로운 value 의 리턴값으로 바꿔 렌더링한다. (rarely needed)
아래 예제는 setState의 동작 순서를 확인할 수 있는 코드이다.
개선 전 코드에서 버튼을 클릭했을 때, setCount는 비동기적으로 작동하기 때문에 아래의 조건문이 먼저 실행되고, count는 이전 state를 가리켜 count가 3으로 업데이트 됨에도 불구하고 age도 같이 상승하는 것을 볼 수 있다.
✅ 하나의 함수 안에서 하나의 state 여러 번 변경하기
하나의 함수 안에서 setState를 여러 번 사용하면 즉각적으로 변경된 value 값으로 업데이트 될 것이라고 예상하지만 아니다.
아래의 코드를 실행해보면 setCount를 세 번 실행했기에 3이 출력될 것이라는 예상과는 달리 1이 출력되는 것을 확인할 수 있다.
const [count, setCount] = useState(0)
function handleClick() {
setCount(count + 1) // 0 + 1
setCount(count + 1) // 0 + 1
setCount(count + 1) // 0 + 1
}
setState 안에 updater function을 넣어주면 문제가 해결된다.
updater function을 넣어 렌더링하게 되면 내부적으로 큐에 pending state 로 들어가고, 그걸 바탕으로 next state를 계산하게 된다.
const [count, setCount] = useState(0)
function handleClick() {
setCount(n => n + 1) // 0 + 1
setCount(n => n + 1) // 1 + 1
setCount(n => n + 1) // 2 + 1
}
✅ 배열/객체 state 값 변경하기
setState는 prev state와 next state가 참조하는 메모리 주소가 같으면 값이 변화하지 않았다고 인식해 리렌더링을 일으키지 않는다.
따라서 state를 업데이트 시키기 위해선 기존 배열/객체를 수정하는 것이 아니라 새로운 배열/객체를 반환해야 한다.
const [obj, setObj] = useState({ name: 'sun'});
obj.name = 'zoo'; // X (직접 바꾸면 안됨)
setObj(obj.name = 'zoo'); // X (원본 객체를 수정하면 안됨)
setObj({...obj, name: 'zoo'}); // O (원본 객체를 복사한 새로운 객체를 생성 및 state 수정)
💖 배열 state 변경 시 사용하는 메서드
- 요소 첨가
- 사용 X : push, unshift
- 사용 O : concat, [...arr] 스프레드 구문
- 요소 제거
- 사용 X : pop, shift, splice
- 사용 O : filter, slice
- 요소 교체
- 사용 X : splice, arr[i] = value
- 사용 O : map
- 요소 정렬
- 사용 X : reverse, sort
- 사용 O : 원본 배열을 복사한 새 배열에서 정렬
'Front-End > React' 카테고리의 다른 글
| [React] Virtual DOM 동작 원리와 이해 (0) | 2023.04.03 |
|---|---|
| [React] React.memo, useMemo란 무엇인가 (0) | 2023.03.23 |
| [React] useEffect란 무엇인가 (0) | 2023.03.16 |
| [React] Custom Hook - 초기 렌더링 때 useEffect 실행 막기 (0) | 2023.03.14 |
| [React] useReducer란 무엇인가 (0) | 2023.03.13 |