React 04. useState

윤태현·2023년 6월 27일
0

REACT

목록 보기
4/20
post-thumbnail

📑 useState

useState란?

  • React의 내장 Hook 중 하나로, 함수형 컴포넌트에서 상태를 관리할 수 있게 해줌
  • 클래스 컴포넌트에서의 this.state, this.setState의 기능을 수행

📑 useState 장점

  1. 함수형 컴포넌트의 간결성을 유지하면서 동시에 상태 관리가 가능함

  2. 여러 번 호출하여 여러 개의 상태를 관리할 수 있음, 이를 통해 서로 관련 있는 상태들을 그룹화하고 독립적인 상태 로직을 분리하여 재사용성을 높일 수 있음

  3. 테스트와 디버깅이 쉬움 (상태와 로직이 명확하게 분리되어 있기 때문)


📑 useState 사용

1. useState import

import React, { useState } from 'react';

2. 상태 생성하기

  • useState는 초기 상태 값을 인자로 받고, 상태 변수와 해당 상태를 업데이트하는 변수를 배열로 반환
function App() {
	const [count, setCount] = useState(0);
    // ...
}

3. 상태 업데이트하기

  • 상태 업데이트 함수를 사용해서 상태 값을 업데이트

3-1. 숫자 업데이트

const [count, setCount] = useState(0);

setCount(1);

3-2. 문자열 업데이트

const [text, setText] = useState('');
  
setText('Hello, World');

3-3. 배열 업데이트

const [array, setArray] = useState([]);

// 배열로 상태 업데이트
setArray([1, 2, 3]);

// 배열에 요소 추가
setArray([...prevArray, 4]);	// push
setArray([0, ...prevArray]);	// unshift

// 요소를 추가할 때 위와 같이 하면 문제없이 동작하지만 권장하지 않는다.
// 비동기적으로 실행 되기 때문에 바로 업데이트가 되지 않는다. (주의할 점에서 설명)
// 여러번 상태 업데이트를 할 경우 아래와 같이 업데이트를 권장
setArray(prevArray => [...prevArray, 4]);	// push
setArray(prevArray => [0, ...prevArray]);	// unshift

3-4. 객체 업데이트

const [object, setObject] = useState({});

// 객체로 상태 업데이트
setObject({ name: 'yoon', age: 29 }); 

// 객체의 프로퍼티 업데이트
setObject(prevObject => ({ ...prevObject, live: 'incheon' }) );

📑 useState 주의할 점

1. 직접 상태 수정하지 않기

  • 상태를 수정할 때는 반드시 상태 변경 함수를 이용해야 함.
  • 상태를 직접 수정하면 React는 상태가 변경되었는지 알 수 없어서 컴포넌트를 재렌더링하지 않을 수 있음
// Bad
const [count, setCount] = useState(0);
count = 1; // 직접 수정하면 안 됩니다.

// Good
setCount(1); // 상태 변경 함수를 사용하세요.

2. 컴포넌트 바깥에서 사용하지 않기

  • Hook은 컴포넌트 함수 내에서만 호출 해야 함.
  • 컴포넌트 함수 외부, 반복문, 조건문, 중첩된 함수 등에서 Hook을 호출하면 안 됨, 이는 React가 Hook의 호출 순서를 기반으로 내부 상태를 관리하기 때문.

3. 비동기적으로 상태를 업데이트

  • 상태 업데이트 이후 즉시 해당 상태에 접근하면 예상하지 못한 결과를 볼 수 있기 때문에, 바로 접근하려면 따로 만들어줘야 함
// bad
function App() {
	const [count, setCount] = useState(0);
  
    const onClick = () => {
    	setCount(count+1);
        console.log(count)	// +1 하기 전의 값을 가져옴
    }
    return <button onClick={onClick}>{count}</button>
}
// Good
function App() {
	const [count, setCount] = useState(0);
  
    const onClick = () => {
        const nextCount = count+1;
    	setCount(nextCount);
        console.log(nextCount)	// +1 한 값을 콘솔로 봐야 함
    }
    return <button onClick={onClick}>{count}</button>
}
  • 여러 번 상태를 변경할 경우 함수 업데이트를 사용해야 함
// Bad
setCount(count + 1);
setCount(count + 1); // 이전 변경이 반영되지 않을 수 있습니다.

// Good
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1); // 항상 최신 상태를 반영합니다.

4. 컴포넌트의 렌더링 과정 중 상태 업데이트 하지 않기

  • 상태 업데이트는 컴포넌트의 재렌더링을 일으키기 때문에 무한 루프에 빠짐
  • 렌더링 -> 상태 업데이트 -> 재렌더링 -> 상태 업데이트 -> 재렌더링 -> ...
  • 상태 업데이트는 이벤트 핸들러나 생명주기 메서드 등에서 처리해야 함
// bad (무한 루프에 빠짐)
function App() {
	const [count, setCount] = useState(0);
  
    setCount(count => count+1);
  	return <h1>{count}</h1>
}
// 해결법 (이벤트 핸들러를 사용해서 처리를 진행)
function App() {
	const [count, setCount] = useState(0);
  
    const onClick = () => {
    	setCount(count => count+1);
    }
    
  	return (
      	<>
          	<h1>{count}</h1>
         	<button onClick={onClick}>클릭</button>
        </>
    )
}

5. 컴포넌트가 렌더링될 때마다 호출이 됨

  • useState의 초기값에 복잡하고 무거운 계산이 필요한 함수를 넣으면 컴포넌트가 렌더링될 때마다 해당 함수가 호출되어 성능에 문제를 일으킬 수 있음.
// 성능에 문제가 생길 수 있음
const heavyWork = () => {
	console.log('시간이 오래 걸리는 엄청 무거운 작업');
    return { name: '홍길동', age: 20};
}

function App() {
	const [user, setUser] = useState(heavyWork);
}

// 이런 식으로 사용할 경우 컴포넌트가 렌더링될 때마다 heavyWork() 함수가 호출됨.
  • useState가 함수를 초기값으로 받을 수 있는 기능을 제공 (lazy initialization), 초기 상태가 계산 비용이 큰 경우에 유용하게 사용
// 해결법
const heavyWork = () => {
	console.log('시간이 오래 걸리는 엄청 무거운 작업');
    return { name: '홍길동', age: 20};
}

function App() {
	const [user, setUser] = useState(() => heavyWork());
}
  • useState 초기값에 콜백을 넣어줘서 heavyWork() 함수가 맨 처음 렌더링될 때만 호출하게 만듬

0개의 댓글