본문 바로가기
카테고리 없음

state

by 용용이아바이 2024. 4. 29.
728x90

리액트에서 state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다. props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사요할 수 있다. props를 바꾸려면 부모 컴포넌트에서 바꾸어야 한다. 예를 들어 App 컴포넌트에서 MyComponent 를 사용할 때 props를 바꿔야 값이 변경될 수 있다. 반면 MyComponent에서는 전달받은 name 값을 직접 바꿀 수 없다. 리액트에는 두가지 종류의 state가 있다. 하나는 클래스형 컴포넌트가 지니고 있는 state이고, 다른 하나는 함수형 컴포넌트에서 useState라는 함수를 통해 사용하는 state이다.

클래스형 컴포넌트의 state

Counter.js 파일을 src 디렉터리에 생성한다.

import React, { Component } from 'react';

class Counter extends Component {
	constructor(props) {
    	super(props);
        
        // state의 초기값 설정
        this.state = {
        	number: 0
        };
    }
}
render() {
	const { number } = this.state; // state를 조회할 때 this.state로 조회한다.
    return (
    	<div>
        	<h1>{ number }</h1>
            <button
            // onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정한다.
            onClick = {() => {
            	this.setState({ number: number + 1});
            }}
            > +1
            </button>
        </div>
    );
}

export default Counter;

컴포넌트에 state를 설정할 때는 다음과 같이 constructor 생성자 메서드를 작성해야 한다.

클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해야 한다. 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출한다.

그 다음에는 this.state 값에 초기값을 설정한다. 컴포넌트의 state는 객체 형식이어야 한다.

render 함수에서 현재 state를 조회할 때는 this.state를 조회하면 된다. 그리고 button 안에 onClick이라는 값을 props로 넣어 주었는데, 이는 버튼이 클릭될 때 호출시킬 함수를 설정할 수 있게 한다. 이벤트로 설정할 함수를 넣어 줄 때는 화살표 함수 문법을 사용하여 넣어야 한다. 함수 내부에서는 this.setState라는 함수를 사용했는데, 이 함수가 state값을 바꿀 수 있게 한다. 

import React from 'react';
import Counter from './Counter';

const App = () => {
	return <Counter />;
};

export default App;

 

state 객체 안에 여러 값이 있을 때

state 객체 안에는 여러 값이 있을 수 있다. Counter 컴포넌트를 수정한다.

import React, { Component } from 'react';

class Counter extends Component {
	constructor(props) {
    	super(props);
        
        // state의 초기값 설정
        this.state = {
        	number: 0,
            fixed: 0
        };
    }
}
render() {
	const { number, fixed } = this.state; // state를 조회할 때 this.state로 조회한다.
    return (
    	<div>
        	<h1>{ number }</h1>
            <h1>바뀌지 않는 값: { fixed }</h1>
            <button
            // onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정한다.
            onClick = {() => {
            	this.setState({ number: number + 1});
            }}
            > +1
            </button>
        </div>
    );
}

export default Counter;

 

state를 constructor에서 꺼내기

import React, { Component } from 'react';

class Counter extends Component {
	state = {
    	number: 0,
        fixed: 0
    }
}
render() {
	const { number, fixed } = this.state; // state를 조회할 때 this.state로 조회한다.
    return (
    	<div>
        	<h1>{ number }</h1>
            <h1>바뀌지 않는 값: { fixed }</h1>
            <button
            // onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정한다.
            onClick = {() => {
            	this.setState({ number: number + 1});
            }}
            > +1
            </button>
        </div>
    );
}

export default Counter;

이렇게 하면 constructor 메서드를 선언하지 않고도 state 초기값을 설정할 수 있다. 

 

this.setState에 객체 대신 함수 인자 전달하기

onClick = {() => {
	// this.setState를 사용하여 state에 새로운 값을 넣을 수 있다.
    this.setState({ number: number + 1 });
    this.setState({ number: this.state.number + 1 });
}}

코드를 위와 같이 작성하면 this.setState를 두번 사용하는 것임에도 불구하고 버튼을 클릭할 때 숫자가 1씩 더해진다. this.setState를 사용한다고 해서 state값이 바로 바뀌지 않기 때문이다.

이에 대한 해결책은 this.setState를 사용할 때 객체 대신에 하수를 인자로 넣어주는 것이다. this.setState의 인자로 함수를 넣어 줄 때는 코드를 다음과 같은 형식으로 작성한다.

this.setState((prevState, props) => {
	return {
    	//업데이트하고 싶은 내용
    }
})

여기서 prevState는 기존 상태이고, props는 현재 지니고 있는 props를 의미한다. 업데이트 과정에서 props가 없다면 생략가능한다.

<button
    onClick = { () => {
        this.setState((prevState) => {
            return {
                number: prevState.number + 1
            };
        });
        // 위 코드와 아래 코드는 완전히 똑같은 기능을 한다.
        this.setState(prevState => ({
            number: prevState + 1
        }));
    }}
>1+
</button>

화살표 함수에서 값을 바로 변환하고 싶다면 코드 블록 { }를 생략하면 된다. 예를 들어, 파라미터 a와 b를 받아 와서 합을 구하는 함수를 작성한다면 된다.

const sum = ( a, b ) => a + b;

 

this.setState가 끝난 후 특정 작업 실행하기

setState를 사용하여 값을 업데이트하고 난 다음에 특정 작업을 하고 싶을 때는 setStae의 두번째 파라미터로 콜백 함수를 등록하여 작업을 처리할 수 있다.

<button
    onClick = { () => {
        this.setState(
            {
                number: number + 1
            },
            () => {
                console.log(' setState 호출됨!! ');
                console.log( this.state );
            }
        );
    }}
>1+
</button>

 

함수형 컴포넌트에서 useState 사용하기

 

배열 비구조화 할당

Hooks를 사용하기 전에 배열 비구조화 할당이라는 것을 알아보자. 배열 비구조화 할당은 객체 비구조화 할당과 비슷하다. 즉, 배열 안에 들어 있는 값을 쉽게 추출할 수 있도록 하는 문법이다.

const array = [ 1, 2 ];
const [ one, two ] = array;

 

useState 사용하기

import React, { useState } from 'react';

const Say = () => {
	const [ message, setMessage ] = useSate('');
    const onClickEnter = () => setMessage('안녕!');
    const onClickLeave = () => setMessage('잘가!');
	
    return (
    	<div>
        	<h1>{ message }</h1>
        	<button onClick = { onClickEnter }>입장</button>
            <button onClick = { onClickLeave }>퇴장</button>
        </div>
    );
}
export default Say;

useState 함수의 인자에 상태의 초기값을 넣는다. 클래스형 컴포넌트에서 state 초기값은 객체 형태를 넣어야 하지만 useState에서는 반드시 객체가 아니어도 괜찮다. 함수를 호출하면 배열이 반환되는데, 배열의 첫번째 원소는 현재 상태이고, 두 번째 원소는 상태를 바꾸는 함수다. 이 함수를 setter 함수라고 부른다. 그리고 배열 비구조화 할당을 통해 이름을 자유롭게 정할 수 있다.

import React from 'react';
import Say from './Say';
const App = () => {
	return <Say />;
};

export default App;

 

한 컴포넌트에서 useState 여러 번 사용하기

useState는 한 컴포넌트에서 여러번 사용해도 상과없다.

import React, { useState } from 'react';

const Say = () => {
	const [ message, setMessage ] = useSate('');
    const onClickEnter = () => setMessage('안녕!');
    const onClickLeave = () => setMessage('잘가!');
	
    const [ color, setColor ] = useState('black');
    return (
    	<div>
        	<h1 style = {{ color }}>{ message }</h1>
        	<button onClick = { onClickEnter }>입장</button>
            <button onClick = { onClickLeave }>퇴장</button>
            <button style = {{ color: 'red' }} onClick = { () => setColor('red') }>빨강색</button>
            <button style = {{ color: 'blue' }} onClick = { () => setColor('blue') }>파랑색</button>
            <button style = {{ color: 'green' }} onClick = { () => setColor('green') }>초록색</button>
        </div>
    );
}
export default Say;

 

state를 사용할 때 주의 사항

state값을 바꾸어야 할 때는 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 한다.

아래는 잘못된 코드이다.

// 클래스형 컴포넌트에서
this.state.number = this.state.number + 1;
this.state.array= this.array.push(2);
this.state.object.value = 1;

// 함수형 컴포넌트에서
const [ object, setObject ] = useState({ a: 1, b: 2});
object.b = 3;

사본을 만들어서 업데이트 하자.

// 객체 다루기
const object = { a: 1, b: 2, c: 3};
const nextObject = { ...object, b: 2 }; // 사본을 만들어서 b값만 덮어쓰기

// 배열 다루기
const array = [
	{ id: 1, value: true},
    { id: 2, value: true},
    { id: 3, value: false}
];

let nextArray = array.concat({ id: 4 }); // 새 항목 추가
nextArray.filter(item => item.id !== 2); // id가 2인 항목 제거
nextArray.map(item => (item.id === 1 ?  { ...item, value: false} : item }); // id가 1인 항목의value를 false로 변경

 

728x90