프로그래밍/React

[React] component, props, state

라다디 2022. 3. 9. 09:39

 

컴포넌트

  • 앱을 이루는 최소한의 단위
  • 컴포넌트에는 클래스형 컴포넌트와 함수형 컴포넌트가 존재

클래스형 컴포넌트

class App extends Component {
  render() {
    const name = "리액트";
    return <div className="react">{name}</div>;
  }
}

함수형 컴포넌트

// 일반 함수
function App() {
  const name = '리액트';
  return <div className="react">{name}</div>;
}

// 화살표 함수
const App = () => {
  const name = '리액트';
  return <div className="react">{name}</div>;
}

 

[참고] 일반 함수와 화살표 함수의 this

 

[javascript] 일반 함수와 화살표 함수의 차이 (feat. ES6)

항상 일반 함수와 화살표 함수의 정확한 차이점을 지나쳐 왔습니다. 단순하게 화살표 함수(Arrow function)는 ES6에 새로 나온 문법인 것으로만 인식한 상태로 개발했지만 정확히 알고 적절하게 활용

charming-kyu.tistory.com

 

 

두 컴포넌트의 차이점

  • 클래스형 컴포넌트는 state와 라이프사이클 API 사용 가능
  • 함수형 컴포넌트는 state와 라이프사이클 API 사용 불가능 → (리액트 v16.8 업데이트) Hooks 기능 도입

리액트 공식 매뉴얼에서는 함수형 컴포넌트와 Hooks사용을 권장

 


props

  • properties의 약자
  • 컴포넌트의 속성을 설정할 때 사용
  • props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정 가능

 

JSX 내부에서 props 렌더링

  • props 값은 컴포넌트 함수의 파라미터로 받아 와서 사용 가능
  • props를 렌더링할 때 JSX 내부에서 { }기호로 감싸주면 됨
// props 값 지정
const App = () => {
  return <MyComponent name="React" />;
};
const MyComponent = props => {
  return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>;
};

 

props 디폴트 값 지정

MyComponent.defaultProps = {
  name: '기본 이름'
};

 

태그 사이 내용 보여주기

const App = () => {
  return <MyComponent>리액트</MyComponent>;
};
const MyComponent = props => {
  return (
    <div>
      안녕하세요, 제 이름은 {props.name}입니다.<br />
      children 값은 {props.children}입니다.  
    </div>
  );
};
더보기

결과
안녕하세요, 제 이름은 기본 이름입니다. 
children 값은 리액트입니다. 

 

props 구조 분해

props 값을 조회할 때 마다 앞에 props 키워드 붙이는 것은 번거로움

 구조 분해(비구조화 할당)을 이용하여 내부 값을 바로 추출 가능

const MyComponent = props => {
  const {name, children} = props;
  return (
    <div>
      안녕하세요, 제 이름은 {name}입니다.<br />
      children 값은 {children}입니다.  
    </div>
  );
};

혹은 

const MyComponent = ({name, children}) => {
  return (
    <div>
      안녕하세요, 제 이름은 {name}입니다.<br />
      children 값은 {children}입니다.  
    </div>
  );
};

 

propTypes

  • 필수 props를 지정하거나 props의 타입을 지정할 때 사용

아래처럼 지정시 name은 무조건 문자열 형태로 전달해야 된다는 것을 의미

필수 props는 isRequired를 붙여서 지정

MyComponent.propTypes = {
  name: PropTypes.string,
  favoriteNumber: PropTypes.number.isRequired
};

 

※ 클래스형 컴포넌트에서 props를 사용할 때는 render함수에서 this.props를 조회하면 됨

 


State

  • 컴포넌트 내부에서 바뀔 수 있는 값
더보기

📎 props

  • 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값
  • 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용 가능
  • props를 변경하기 위해서는 부모 컴포넌트에서 바꾸어 주어야 함
  • 두 가지 종류의 state
    • 클래스형 컴포넌트가 지니고 있는 state
    • 함수형 컴포넌트에서 useState 함수를 통해 사용하는 state

 

클래스형 컴포넌트의 state

import React, { Component } from 'react';

class Counter extends Component {
  // part1
  constructor(props) {
    super(props);
    this.state = {
      number: 0;
    };
  }
  // part2
  render() {
    const { number } = this.state; 
    return (
      <div>
        <h1>{number}</h1>
        <button
          onClick={() => {
            this.setState({ number: number + 1});
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

 

# part1

constructor(props) {
  super(props);
  this.state = {
    number: 0;
  };
}
  • 클래스형 컴포넌트에서 constructor(생성자)를 작성할 때는 반드시 super(props)를 호출해야 함
    • → 현재 클러스터형 컴포넌트가 상속하고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출
  • this.state 값에 초깃값을 설정 (클래스형 컴포넌트의 state는 객체 형식이어야 함
더보기

constructor 사용 안하고 state초기값 설정하는 방식

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

 

# part2

render() {
    const { number } = this.state; // state 를 조회 할 때에는 this.state 로 조회합니다.
    return (
      <div>
        <h1>{number}</h1>
        <button
          onClick={() => {
            this.setState({ number: number + 1});
          }}
        >
          +1
        </button>
      </div>
    );
  }
  • button 안에 onClick(버튼이 클릭될 때 호출할 함수를 설정하는 이벤트) props
  • 이벤트로 설정할 함수를 넣어줄 때는 화살표 함수 문법 사용
  • this.setState는 state 값을 바꿀 수 있게 해줌

 

this.setState에 함수 전달

this.setState를 사용하여 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트 됨

 

코드를 아래와 같이 작성한다고 해서 버튼을 클릭할 때 숫자가 2씩 더해지진 않는다는 소리

onClick={() => {
  this.setState({ number: number + 1});
  this.setState({ number: this.state.number + 1 });
}}

 

→ 객체 대신에 함수를 인자로 넣어서 해결

onClick={() => {
  this.setState(prevState => ({
    number: prevState.number + 1
  }));
}}

 

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

setState의 두 번째 파라미터로 콜백 함수를 등록하여 작업 처리 가능

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

 

함수형 컴포넌트의 state

리액트 16.8 이후부터는 useState라는 함수를 사용하여 함수형 컴포넌트에서도 state를 사용할 수 있게 되었음

import React, { useState } from 'react';

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

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

  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;
  • useState의 인자에는 상태의 초기값 (클래스형 컴포넌트와 달리 반드시 객체가 아니어도 됨)
  • useState는 배열을 반환
  • 배열의 첫 번째 원소는 현재 상태, 두 번째 원소는 상태를 바꿔주는 함수(setter)

 

state 사용시 주의 사항

state 값을 바꿀 때는 반드시 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 함

 배열이나 객체를 업데이트 해야할 때는 사본을 만들어서 값을 업데이트하는 방식 사용

  • 배열의 사본은 배열 내장 함수 이용 (filter, map 등)
  • 객체의 사본은 spread 연산자 이용

 

정리

props는 부모 컴포넌트가 설정

state는 컴포넌트 자체적으로 지닌 값  컴포넌트 내부에서 값 업데이트 가능

 

하지만 props를 사용한다고 해서 값이 무조건 고정적인 것은 아님

부모 컴포넌트의 state를 자식 컴포넌트의 props로 전달하고, 자식 컴포넌트에서 특정 이벤트가 발생할 때 부모 컴포넌트의 메소드를 호출하면 props도 유동적으로 사용 가능


📌 아래 문서와 서적의 내용을 정리한 글입니다.