리액트를 다루는 기술 3장 - 컴포넌트

sh·2022년 8월 2일
0

컴포넌트

컴포넌트 선언 방식
1. 함수형 컴포넌트 << 주로 사용
2. 클래스형 컴포넌트

클래스형 컴포넌트

import React, { Component } from "react";

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

props

props는 컴포넌트 속성을 설정할 때 사용하는 요소이다.
props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정한다.

// MyComponent.js
import React from "react";

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

export default MyComponent;

App컴포넌트(부모 컴포넌트)에서 MyComponent의 props 값을 지정

//App.js
import MyComponent from "./MyComponent";

function App() {
  return <MyComponent name="React" />;
}

export default App;

defaultProps

props 값을 따로 지정하지 않았을 때 보여 줄 기본값 설정

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

children

컴포넌트 태그 사이의 내용을 보여주는 props

// App.js
import MyComponent from "./MyComponent";

function App() {
  return <MyComponent>리액트</MyComponent>;
}

export default App;

MyComponent 내부에서 {props.children} 값으로 보여준다.

비구조화 할당으로 props 내부 값 추출

객체에서 값을 추출하는 문법

const {name, children } = props;

함수의 파라미터 부분에서도 사용할 수 있다.

const MyComponent = ({name, children}) => { ... }

propTypes를 통한 props 검증

컴포넌트의 필수 props를 지정하거나 props의 타입을 지정할 때 propTypes를 사용

import PropTypes from 'prop-types';

MyComponent.propTypes = {
  name: PropTypes.string
};

name 값은 무조건 문자열 형태로 전달해야 된다는 것을 의미함
만약 name을 숫자로 전달했을 시 값이 나타나기는 하지만 콘솔에 경고 메시지를 출력한다.

isRequired 를 사용하여 필수 propsTypes 설정

propsTypes를 지정하지 않았을 때 경고 메세지를 띄워줌

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

클래스형 컴포넌트에서 props 사용하기

const {name, favoriteNumber, children } = this.props;

defaultProps와 propsTypes는 똑같은 방식으로 설정할 수도 있고, 다음과 같이 class 내부에서 지정하는 방법도 있다.

class MyComponent extends Component {
  static defaultProps = {
    name: '기본 이름'
  };
  static propTypes = {
    name: PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired
  };
  render(){
    ...
  }
}

state

state 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다. 즉 컴포넌트 자체적으로 지닌 값
props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있다.

클래스형 컴포넌트의 state

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

constructor(props){
  super(props);
  this.state = {
    number: 0
  };
}

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

컴포넌트의 state는 객체 형식이어야 한다.


  render() {
    const { number } = this.state;
    return (
      <div>
        <h1>{number}</h1>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }

render 함수에서 현재 state를 조회할 때는 this.state를 조회하면 된다.
this.setState 함수는 인자로 전달된 객체 안에 들어 있는 값만 바꿔준다.

state를 constructor에서 꺼내기

위에서 state의 초깃값을 지정하기 위해 constructor 메서드를 선언한 방식과는 다른 방식으로 state의 초깃값을 지정할 수 있다.

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

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

this.setState로 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트된다.

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

this.setState를 두 번 사용함에도 불구하고 버튼을 클릭할 때 숫자가 1씩 더해진다.
this.setState를 사용한다고 해서 state 값이 바로 바뀌지는 않기 때문!

해결책: 객체 대신에 함수를 인자로 넣어준다.

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

prevState: 기존 상태, props: 현재 지니고 있는 props

다음과 같이 사용한다.

<button
	onClick={() => {
      this.setState(prevState => {
        return{
          number: prevState.number + 1
        };
      });
      // 위 아래는 같은 기능
      this.setState(prevState => ({
      	number: prevState.number + 1
      }));
    }}
    >
      +1
</button>

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

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

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

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

useState 함수의 인자에는 상태의 초기값을 넣어준다. 클래스형 컴포넌트에서의 state 초기값을 객체 형태로 넣어주는 것과 달리 useState에서는 값의 형태는 자유.

const [message, setMessage] = useState('');

이 방법을 배열 비구조화 할당이라고 한다.

state를 사용할 때 주의 사항

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

배열이나 객체를 업데이트해야 할 때는
1. 배열이나 객체 사본을 만들고 그 사본에 값을 업데이트
2. 그 사본의 상태를 setState 혹은 세터 함수를 통해 업데이트한다.

// 객체
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);
nextArray.map(item => item.id === 1? {...item, value: false} : item)); 

객체에 대한 사본을 만들 때는 spread 연산자 ... 사용
배열에 대한 사본을 만들 때는 배열의 내장 함수들을 활용

0개의 댓글