본문 바로가기
Research/React

React_state 그리고 useState

by RIEM 2023. 10. 23.

props는 부모로부터 받아오는 데이터다. 구조적으로 의존적이다. 그리고 가져온 데이터는 읽을 수만 있고 수정은 불가하다고 한다. 왜 수정이 불가한 걸까. 무튼 props의 데이터는 부모로부터 온다고 했고, 받아온 읽기 전용이라 했으니 데이터를 수정하고 싶으면 부모의 층위에서 데이터를 바꿔주어야 한다.

state는 컴포넌트에서 바꿀 수 있는 값을 말한다. 따라서 부모 컴포넌트에서 state로 데이터를 바꿔준 다음, props로 내리면 자식 컴포넌트에서도 수정된 데이터를 받아올 수 있게 된다.

클래스형 컴포넌트로 state 사용하기

// App.js
import Counter from './Counter';

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

export default App;
//./Counter.js

// 클래스형 컴포넌트

import { Component } from 'react';

class Counter extends Component {
  // 컴포넌트를 생성해주는 메서드
  constructor(props) {
    super(props); // 리액트의 Component 클래스가 가진 생성자 함수 호출
    this.state = {
      number: 0,
      fixedNumber: 0,
    };
  }

  render() {
    const { number, fixedNumber } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h3>fixedNumber : {fixedNumber}</h3>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
          }}
        >
          {' '}
          +{' '}
        </button>
      </div>
    );
  }
}

export default Counter;

클래스에서는 constructor 생성자 함수 내에 this.state라는 객체를 넣어서 state의 초기값을 설정할 수 있다. 그 다음 render() 함수 안에서 this.state를 객체분해 한 다음 이를 return 시 변수로 사용한다.

state 값을 수정하기 위해 button의 onClick 이벤트 발생 시 setState를 반환하는 함수를 넣어준다. 이 버튼을 누르면 number값은 +1씩 증가한다. 단, setState에는 fixedNumber을 넣어주지 않았기에, 이 수는 변하지 않는다. 만약, fixedNumber도 업데이트해주고 싶다면 () => this.setState({number: number+1, fixedNumber: fixedNumber+1})처럼 setState의 인자의 또 다른 프로퍼티로 추가해주면 된다.

// 클래스형 컴포넌트

import { Component } from 'react';

class Counter extends Component {
  // 컴포넌트를 생성해주는 메서드
  // constructor(props) {
  //   super(props); // 리액트의 Component 클래스가 가진 생성자 함수 호출
  //   this.state = {
  //     number: 0,
  //     fixedNumber: 0,
  //   };
  // }

 // constructor없이 state 초기값 설정하기
  state = {
    number: 0,
    fixedNumber: 0,
  };

  render() {
    const { number, fixedNumber } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h3>fixedNumber : {fixedNumber}</h3>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
          }}
        >
          {' '}
          +{' '}
        </button>
      </div>
    );
  }
}

export default Counter;

constructor 없이 state 프로퍼티를 업데이트해주는 방식으로 초기값을 수정할 수도 있다.

// 클래스형 컴포넌트

import { Component } from 'react';

class Counter extends Component {
  // 컴포넌트를 생성해주는 메서드
  // constructor(props) {
  //   super(props); // 리액트의 Component 클래스가 가진 생성자 함수 호출
  //   this.state = {
  //     number: 0,
  //     fixedNumber: 0,
  //   };
  // }

  state = {
    number: 0,
    fixedNumber: 0,
  };

  render() {
    const { number, fixedNumber } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <h3>fixedNumber : {fixedNumber}</h3>
        <button
          onClick={() => {
            this.setState({ number: number + 1 }, () => {
              console.log('setState 호출이 되었어요');
            });
          }}
        >
          {' '}
          +{' '}
        </button>
      </div>
    );
  }
}

export default Counter;

setState의 두번째 인자로 함수를 넣을 수 있다. setState가 수행된 다음 자동으로 무언가를 실행할 수 있게 해주는데, 여기서는 단순 로그를 찍도록 만들었다. setState에 여러 인자가 들어갈 수 있는 것은 몰랐다.

UseState

리액트 16.8 버전 이전까지는 함수 컴포넌트에서 state를 사용할 수 없었다고 한다. 이후 Hooks이라는 기술을 활용하여 useState라는 함수로 state를 사용할 수 있도록 업데이트 되었다. 리액트 팀은 함수 컴포넌트와 Hooks 사용을 권하므로, useState를 쓰도록 하자.

import Say from './Say';

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

export default App;
import { useState } from 'react';

const Say = () => {
  const [message, setMessage] = useState('');
  const onClickEnter = () => setMessage('Hi guys');
  const onClickLeave = () => setMessage('Bye~');

  return (
    <div>
      <button onClick={onClickEnter}>Hi</button>
      <button onClick={onClickLeave}>Bye</button>
      <h1>{message}</h1>
    </div>
  );
};

export default Say;

import { useState } from 'react';

const Say = () => {
  const [message, setMessage] = useState('');
  const onClickEnter = () => setMessage('Hi guys');
  const onClickLeave = () => setMessage('Bye~');

  const [color, setColor] = useState('black');

  return (
    <div>
      <button onClick={onClickEnter}>Hi</button>
      <button onClick={onClickLeave}>Bye</button>

      <h1 style={{ color }}>{message}</h1>

      <button style={{ color: 'red' }} onClick={() => setColor('red')}>
        Red
      </button>
      <button style={{ color: 'green' }} onClick={() => setColor('green')}>
        green
      </button>
      <button style={{ color: 'blue' }} onClick={() => setColor('blue')}>
        blue
      </button>
    </div>
  );
};

export default Say;

state 사용 시 주의 사항

state값은 setState나 useState로 받은 세터함수로만 바꿔야 한다.

클래스형 컴포넌트의 경우 this.state.number = this.state.nuber + 1 이런 식으로 바꾸면 안된다. 함수형 컴포넌트의 경우, const [object, setObject] = useState({...}); object.name = 'changedName' 이런 식으로 자신이 직접 바꾸려 하면 안된다. 세터 함수를 통해 바꾸도록 리액트에게 지시해야 한다. 만약 여러 값이 들어있는 배열이나 객체의 경우, 사본을 복사하여 사본을 수정하고 이를 다시 세터함수에 넣는 방식으로 업데이트하면 된다.

댓글