[리액트] 3. 컴포넌트(2)

PYOUNANI·2022년 10월 1일
0

React

목록 보기
3/9
post-thumbnail

3. 컴포넌트

3-3. state(상태)

state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다. 리액트에는 두 가지 종류의 state가 있다. 클래스형 컴포넌트가 지니고 있는 state이 있고, 함수 컴포넌트에서 useState 함수를 통해 사용할 수도 있다.


3-3-1. 클래스형 컴포넌트의 state

// Counter.js
import { Component } from 'react';

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

export default Counter;

위에 코드에 대해 알아보자.

constructor(props){
    super(props);
    this.state ={      
      number: 0
    };
  }
  • constructor 메서드(생성자)를 작성해 컴포넌트에 state를 설정함
  • super(인자 리스트); 가 호출되면 현재 클래스형 컴포넌트(Counter)의 부모 클래스(react의 Component 클래스)가 지닌 생성자 함수를 호출함
  • this.state 값에 초기값 설정, 컴포넌트의 state는 객체 형식이어야 함
 render() {
    const { number } = this.state;
    return (
      <div>
        <h1>{number}</h1>
        <button
        onClick={() => {
          this.setState({ number: number + 1});
        }}
        >
          +1
        </button>
      </div>
    );
  }
  • 현재 state를 조회할 때는 this.state로 조회
  • onclick을 props로 넣어주어, 버튼이 클릭될 때 호출시킬 함수 설정 (='이벤트를 설정한다'라고 하며, 4장에서 다룸)
// App.js
import Counter from './Counter';

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

export default App;

3-3-2. state 객체 안에 여러 값이 있을 때

state 객테 안에는 여러 값이 존재할 수 있다.

// Counter.js
import { Component } from 'react';

class Counter extends Component {
  constructor(props){
    super(props);
    this.state ={         // state의 초기값 설정
      number: 0
      fixedNumber: 0 
    };
  }
  
  render() {
    const { number, fixedNumber } = this.state;    
    return (
      <div>
        <h1>{number}</h1>
      	<h2>바꾸지 않는 값: {fixedNumber}</h2>
        <button
        onClick={() => {
          this.setState({ number: number + 1});
        }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

this.setState 함수의 인자로 전달하지 않으면 함수 호출 시에도 값이 바뀌지 않는다.

3-3-3. state를 constructor에서 꺼내기

앞에서느 state 값을 초기화하기 위해 constructor 메서드(생성자)를 선언해주었는데 다른 방식으로도 초기값을 설정할 수 있다.

// Counter.js
import { Component } from 'react';

class Counter extends Component {
  state = {        // 이부분을 변경함
    number: 0,
    fixedNumber: 0
  };

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

export default Counter;

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

this.setState를 사용하여 state에 새로운 값을 업데이트할 때는 상태가 비동기적으로 업데이트된다. 다음과 같이 onClick에 설정한 함수 내부에서 this.setState를 두 번 호출해도 값은 1만 더해진다. 이유는 this.setState를 사용한다고 해서 state 값이 바로 바뀌지는 않기 때문이다.

// Counter.js

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

따라서 this.setState를 사용할 때 객체 대신 함수를 인자로 넣어주면 된다.

// Counter.js

onClick={() => {
          // this.setState를 사용하여 state에 새로운 값을 넣을 수 있음
          this.setState(prevState => {
            return {
              number: prevState.number +1
            };
          });
          // 위 코드와 아래 코드는 완전히 똑같은 기능
          //아래 코드는 함수에서 바로 객체를 반환한다는 의미
          this.setState(prevState => ({
            number: prevState.number + 1
          }));
        }}

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

setState의 두 번째 매개변수로 콜백 함수를 등록하여 작업 처리할 수 있다.

// Counter.js

onClick={() => {
            this.setState(
              { number: number + 1 },
              () => {
                console.log('방금 setState가 호출되었습니다.');
                console.log(this.state);
              }
            );
          }}

3. 컴포넌트

3-4. useState

리액트 16.8 버전부터는 Hooks 기능 중 useState라는 함수를 사용하면, 함수 컴포넌트에서도 state를 이용할 수 있게 되었다.


3-4-1. 배열 비구조화 할당

객체 비구조화 할당과 비슷하게, 배열 안의 값을 추출하는 문법이다.

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

// 위 코드를 배열 비구조화 할당을 사용
const array = [1, 2];
const [one, two] = array;

3-4-2. useState 사용하기

// Say.js
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>
      <h1>{message}</h1>
    </div>
  );
};

export default Say;

위의 코드에 대해 알아보자.

  • useState 함수의 인자에는 상태의 초깃값을 넣어 줍니다.
  • 클래스형 컴포넌트에서의 state 초깃값은 객체로 넣어줘야 했는데 useState 에서는 반드시 객체일 필요는 없다.
  • 함수를 호출하면 배열이 반환된다.
  • 배열의 첫 번째 원소는 현재 상태이고 두 번째 원소는 상태를 바꾸어 주는 함수이다. 이 함수를 세터함수라고 한다.
// App.js
import Say from './Say';

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

export default App;

3-4-3. 한 컴포넌트에서 useState 여러 번 사용하기

 import { useState } from 'react';

const Say = () => {
  const [message, setMessage] = useState('');
  const onClickEnter = () => setMessage('안녕하세요!');
  const onClickLeave = () => setMessage('안녕히 가세요!');

  const [color, setColor] = useState('black');  // 새로 추가된 상태(state)

  return (
    <div>
      <button onClick={onClickEnter}>입장</button>
      <button onClick={onClickLeave}>퇴장</button>
      <h1 style ={{ color }}>{message}</h1>
      <button style={{ color: 'red' }} onClick={() => setColor('red')}>
        빨간색
      </button>
      <button style={{ color: 'green' }} onClick={() => setColor('green')}>
        초록색
      </button>
      <button style={{ color: 'blue' }} onClick={() => setColor('blue')}>
        파란색
      </button>
    </div>
  );
};

export default Say;

3. 컴포넌트

3-5. state를 사용할 때 주의 사항


state의 값을 변경하려면 상태(state)에 직접 접근하는 것이 아니라
setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 한다.

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

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

배열이나 객체를 업데이트할 때에는 배열이나 객체의 사본을 만들어 업데이트할 값을 저장한 후,
그 사본을 setState 혹은 세터 함수를 통해 업데이트해야 한다.

  • 객체에 대한 사본을 만들 때: spread 연산자라 불리는 ...을 사용하여 처리
  • 배열에 대한 사본을 만들 때: 배열의 내장 함수들을 활용

이에 대한 자세한 내용은 이후에 배워 보겠다.

// 객체 다루기
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: 2}); // 새 항목 추가
nextArray.filter(item -> item.id !==2); // id가 2인 항목 제거
nextArray.map(item => (item.id === 1 ? { ...item, value: false } : item)); // id가 1인 항목의 value를 false로 설정

0개의 댓글