React - State

이소라·2022년 7월 25일
0

React

목록 보기
3/23

State

  • state : 컴포넌트 내부에서 바뀔 수 있는 값

  • props : 부모 컴포넌트가 설정하는 값, 자식 컴포넌트는 props를 읽기 전용으로만 사용할 수 있음

  • 하향식 데이터 흐름 (단방향식 데이터 흐름)

    • 모든 state는 항상 특정한 컴포넌트가 소유하고 있음
    • 컴포넌트는 자신의 state를 자식 컴포넌트에 props로 전달할 수 있음
    • state에서 파생된 UI 또는 데이터는 트리구조에서 본인 컴포넌트의 아래에 있는 컴포넌트에만 영향을 미침



클래스형 컴포넌트의 state

  • constructor 메서드 내부에서 state를 설정하거나 클래스 내부에서 state를 설정함

constructor 메서드 내부에서 state 설정

import { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    };
  }
}
  • 클래스형 컴포넌트에서 constructor를 작성할 때 반드시 super(props)를 호출해야 함
    • super(props) 함수가 호출되면 현재 클래스형 컴포넌트가 상속 받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해줌
  • this.state에 상태 초기값을 설정함
    • 클래스형 컴포넌트의 state는 객체 형식이어야 함
import { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    };
  }
  
  render() {
    const { number } = this.state;
    return (
      <div>
        <h1>{number}</h1>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
          }}
         >
          +1
        </button>
      </div>
    )
  }
}
  • state를 조회할 때 this.state로 조회함
  • state를 변경할 때 this.setState를 사용함

state 객체 안에 여러 값이 존재할 경우

import { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0,
      fixedNumber: 0
    };
  }
  
  render() {
    const { number, fixedNumber } = this.state;
    return (
      <div>
        <h1>{number}</h1>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
          }}
         >
          +1
        </button>
      </div>
    )
  }
}
  • state 객체 내부에 값이 여러 개 있을 경우, this.setState 함수의 인자로 전달되는 값만 변경됨

constructor 메서드 내부가 아닌 클래스 내부에서 state 설정

import { Component } from 'react';

class Counter extends Component {
  state = {
    number: 0,
    fixedNumber: 0
  };
  
  render() {
    const { number, fixedNumber } = this.state;
    return (...);
  }
}

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

  • this.setState를 사용하여 state 값을 업데이트할 때 상태가 비동기적으로 업데이트됨
  • 다음 state를 계산할 때 현재 state를 사용하기 위해서 this.setState에 객체 대신 인자를 인자로 받음
this.setState((prevState, props) => {
  return {
    // 업데이트하고 싶은 내용
  }
})
  • 위 코드에서 prevState는 기존 상태, props는 현재 지니고 있는 props를 가리킴
    • 상태 업데이트 시 props가 필요하지 않다면 생략 가능함
<button
  onClick={() => {
    this.setState(prevState => {
      return {
        number: prevState.number + 1
      };
    });
  }}
>
 +1
</button>

// 화살표 함수에서 값을 바로 반환하고 싶으면 {}를 생략 가능함
<button
  onClick={() => {
    this.setState(prevState => ({
      number: prevState.number + 1
    }));
  }}
 >
  +1
 </button>

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

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

클래스형 컴포넌트에서 Life Cylcle 메서드 사용하기

  • componentDidMount() : 클래스 컴포넌트가 DOM에 렌더링된 이후에 실행됨
  • componentWillUnmount : 클래스 컴포넌트가 DOM에서 삭제된 이후에 실행됨
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  • 메서드 호출 순서
    1. Clock 컴포넌트의 constructor가 호출되면서 this.state를 현재 시각이 포함된 객체로 초기화함
    2. Clock 컴포넌트의 render() 메소드를 호출하고 렌더링의 출력값을 DOM에 삽입함
    3. componentDidMoutn() 메소드를 호출함, Clock 컴포넌트는 매초마다 컴포넌트의 tick() 메서드를 호출함
    4. tick() 메서드가 호출되면서 그 안의 setState() 함수가 실행됨, state가 현재 시각을 포함하는 객체로 변경됨
    5. React가 Clock 컴포넌트의 state가 변경되었다는 것을 인지하고, render() 메서드를 호출함, 변경된 렌더링 출력값이 DOM에 업데이트됨
    6. Clock 컴포넌트가 DOM에서 한 번이라도 삭제되었다면 compontWillUnmout() 메서드를 호출함



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

  • useState 함수를 사용하여 함수 컴포넌트에서 state를 사용할 수 있음

useState 사용하기

import { useState } from 'react';

const Say = () => {
  const [message, setMessage] = useState('');
  const onClickEnter = () => setMessage('안녕하세요');
  const onClickLeave = () => setMessage('안녕가세요');
  
  return (
    <div>
      <button onClick={onClickEnter}>입장</button>
      <button onClick={onClickLeave}>퇴장</button>
    </div>
  );
};

export default Say;
  • useState 함수로 state의 초기값을 설정할 때 값의 형태는 자유임 (숫자, 문자열, 객체, 배열 등)
  • useState 함수를 호출하면 배열이 반환됨
    • 배열의 첫 번째 요소 : 현재 상태 (state)
    • 배열의 두 번째 요소 : 세터 함수 (Setter)
    • 배열의 비구조화 할당(destructuring assignment)을 통해 이름을 자유롭게 지어줄 수 있음

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

  • useState는 한 컴포넌트에서 여러 번 사용 가능함
import { useState } from 'react';

const Say = () => {
  const [message, setMessage] = useState('');
  const [color, setColor] = useState('black');
  const onClickEnter = () => setMessage('안녕하세요');
  const onClickLeave = () => setMessage('안녕가세요');
  
  return (
    <div>
      <button onClick={onClickEnter}>입장</button>
      <button onClick={onClickLeave}>퇴장</button>
      <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의 세터 함수를 사용해야함
// bad
this.state.number = this.state.number + 1;
const [object, setObject] = useState({ a: 1, b: 1 });
object.b = 2;

// good
this.setState({ number : number + 1});
const [object, setObject] = useState({ a: 1, b: 1 });
setObject({ ...object, b: 2});
  • state가 배열이나 객체일 경우, 배열이나 객체의 사본을 만들고 사본의 값을 변경한 다음 setState나 세터 함수의 인자에 사본을 넣어서 변경된 값을 업데이트함
    • 객체의 사본을 만들 때는 spread 연산자(...)를 사용함
    • 배열의 사본을 만들 때는 배열의 내장 함수들(map, filter, concat 등)를 사용함
const object = { a: 1, b: 2, c: 3 };
const nextObject = { ...object, b: 2};

const array = [
  {id: 1, value: true},
  {id: 2, value: true},
  {id: 3, value: false},
];
const nextArray = array.concat({ id: 4});
nextArray.filter(item => item.id !== 2);
nextArray.map(item => (item === 1 ? {...item, value: false} : item));

0개의 댓글