react

리액트 state(상태)란?

hoazzinews 2024. 12. 5. 11:02

이번 시간에는 'state'에 대해서 살펴보겠습니다.

 

1. state가 뭔가요?

state는 우리말로 '상태' 또는 '상태 값'이라고 합니다.

state는 특정 데이터를 담을 수 있는 변수와 같은 개념이라고 생각하면 됩니다. 사람으로 치면 사람의 이름, 연락처, 메일 주소 등이 되겠네요.

리액트에서도 프로그램에서 필요한 데이터를 state에 저장하고 사용합니다. 그리고 이렇게 저장한 데이터는 언제든지 변경 가능합니다. 

 

2. state를 어디에 사용하나요?

리액트에서는 state를 컴포넌트에서 사용합니다. 사람으로 치면 컴포넌트를 사람이라고 할 수 있고, 사람의 이름, 연락처, 메일을 컴포넌트의 state라고 할 수 있습니다.

 

그래서 일반적으로 state를 다른 말로 '컴포넌트 state' 또는 '컴포넌트 상태 값'이라고 합니다.

결론적으로 컴포넌트가 가져야 하는 '상태 값'을 state에 저장해 놓고 사용하는 거죠.

컴포넌트는 객체로 독립적입니다. 따라서 각각의 컴포넌트는 자기만의 state를 가질 수 있습니다. 마치 사람의 이름, 연락처, 메일이 다르듯이요. 

 

3. state 변화와 컴포넌트 재 렌더링

state가 무엇인지 알았다면 이제 정말 중요한 내용이 있습니다. 컴포넌트는 state가 변경되면 해당 컴포넌트는 재 렌더링 되고 실제 돔에 업데이트 됩니다.

state가 변경되면 컴포넌트는 재 렌더링 되고 실제돔에 업데이트 합니다.

 

4. state를 어떻게 사용하나요?

state가 무엇이고 state가 변경되면 해당 컴포넌트가 재 렌더링되고 실제 돔에 업데이트되는 것을 이해했습니다. 그럼 코드로는 어떻게 구현할까요? 함수형 컴포넌트에서는 state를 편리하게 사용하도록 useState 훅을 제공합니다. 즉, 개발자는 useState 훅을 이용해서 state를 생성하고 관리할 수 있습니다. 다음은 useState 훅의 기본 문법입니다.


  - state 이름: state는 변수와 같다고 했죠. 즉 변수 이름으로 개발자가 작명하면 됩니다.

  - state 변경 함수 이름: state 값을 변경하는 함수 이름으로 개발자가 작명하면 됩니다. 일반적으로 'setter(세터)'라고 부릅니다.

  - state 초기 값: 컴포넌트가 마운트 될 때 '초기 state 값'으로 숫자, 문자열, 객체 등 모든 데이터 타입이 올수 있습니다.


개발자는 '백문이 불여일타'겠죠. 바로 코드로 확인하겠습니다.

const [name, setName] = useState('hong gildong');	// 'name' state 선언

useState()를 사용해서 'name' state를 선언합니다. 그리고 'name'의 값을 변경할 수 있는 setName도 선언합니다. 이렇게 하면 컴포넌트는 'name' state와 'setName' 세터 함수를 가지게 됩니다.

※ 참고. useState()는 배열을 반환합니다. 그리고 반환된 배열의 첫 번째에는 'state 이름'을, 두 번째에는 '세터 함수'가 있습니다.

 

다음 코드는 'name' state 값을 화면에 출력하는 코드와 출력 결과입니다.

const [name, setName] = useState('hong gildong');	// 'name' state 선언

return (
    <>
        <input 
            type="text" 
            value={name}        // value에 'name' 적용
        />
    </>
        
);

input의 value 속성에 'name' 을 적용해서 화면에 출력했습니다.

 

이제 사용자가 'name'을 변경하고 변경된 'name'을 화면에 출력해 보겠습니다. <input>에 onChange 이벤트 핸들러를 추가하고 사용자가 값을 변경할 때마다 setName()을 호출해서 'name'을 변경합니다.

const [name, setName] = useState('hong gildong');  // 'name' state 선언

return (
    <>
        <input 
            type="text" 
            value={name}                           // value에 'name' 적용 
            onChange={(e) => {
                setName(e.target.value);           // 'name' 변경 

            }}
        />
    </>
        
);

 

onChange에 의해서 사용자가 새로운 내용을 입력하면 setName()으로 'name' 값을 변경합니다. 그러면 state가 변경 되기 때문에 컴포넌트는 재 렌더링 되고 실제 돔에 업데이트됩니다. 업데이트된 컴포넌트는 'name' 값을 <input>에 출력합니다.

state 변경으로 컴포넌트가 재 렌더링되고 실제 돔에 업데이트 됐습니다.

 

이쯤 해서 여러분은 궁금증을 가질 수 있습니다.

사용자가 입력한 값으로 'name'을 변경한 것은 알겠는데, 정말 컴포넌트가 업데이트돼서 변경된 'name'을 <input>에 출력한 걸까? 

 

이런 궁금증은 로그로 확인해 볼 수 있습니다. 예전에 살펴본 '컴포넌트 생명주기'와 'useEffect 훅' 기억하시죠~

useEffect를 이용해서 정말 'name'이 변경될 때마다 컴포넌트가 업데이트되는지 확인할 수 있습니다. 다음은 useEffect를 추가한 코드입니다.

const [name, setName] = useState('hong gildong');   // 'name' state 선언

useEffect(() => {
    console.log('name: ', name);
    
});
    
return (
    <>
        <input 
            type="text" 
            value={name}                            // value에 'name' 적용 
            onChange={(e) => {
                setName(e.target.value);            // 'name' 변경 

            }}
        />
    </>
        
);

 

 

useEffect는 컴포넌트가 최초 마운트 되면 콜백 함수를 호출하고, 이후 컴포넌트가 업데이트될 때마다 계속해서 콜백 함수를 호출합니다. 지금은 콜백 함수가 'name'을 콘솔에 출력합니다. 이렇게 하면 'name' 이 변경될 때마다 컴포넌트가 재 렌더링과 업데이트되는 것을 확인할 수 있겠죠~

컴포넌트 마운트 시 'name' 출력
컴포넌트 업데이트 시 'name' 출력
컴포넌트 업데이트 시 'name' 출력
컴포넌트 업데이트 시 'name' 출력

 

다음은 'phone' state를 추가하고 <input>에 변경 값을 입력 후,  modify 버튼을 클릭했을 때 state가 변경되는 코드입니다. 스스로 코드를 '한땀 한땀' 이해하다 보면 state에 익숙해질 수 있습니다. 

const [name, setName] = useState('hong gildong');     
const [phone, setPhone] = useState('010-1234-5678');

const [inputName, setInputName] = useState(name);     
const [inputPhone, setInputPhone] = useState(phone);

useEffect(() => {
    console.log('name: ', name);
    console.log('phone: ', phone);

});

return (
    <>
        <h3>이름: {name}</h3>
        <input 
            type="text" 
            value={inputName}
            onChange={(e) => {
                setInputName(e.target.value);

            }}
        /><button onClick={() => {
            setName(inputName);

        }}>modify name</button>

        <hr />

        <h3>연락처: {phone}</h3>
        <input 
            type="text" 
            value={inputPhone}
            onChange={(e) => {
                setInputPhone(e.target.value);

            }}
        /><button onClick={() => {
            setPhone(inputPhone);

        }}>modify phone</button>

    </>
    
);

 

참고로 useEffect에서 모든 state( 'name', 'phone', 'inputName', 'inputPhone' )의 값 변경에 따른 로그가 너무 많이 출력된다면 '의존성 배열'을 이용해서 'name'과 'phone'이 변경될 때만 로그를 출력하도록 합니다.

useEffect(() => {
    console.log('name: ', name);
    console.log('phone: ', phone);

}, [name, phone]);		// 'name'과 'phone' 변경 시에만 콜백 함수 호출

 

이번 시간에는 state 개념과 이를 이용하는 useState 훅에 대해서 살펴봤습니다.