hyeonzzz's Tech Blog

[리액트를 다루는 기술] 3장 컴포넌트 본문

React

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

hyeonzzz 2023. 1. 16. 21:42

3장 컴포넌트

3.1 클래스형 컴포넌트

● 컴포넌트를 선언하는 방식

- 함수 컴포넌트

-클래스형 컴포넌트

 

● 차이점

클래스형 컴포넌트 -> state 기능, 라이프 사이클 기능, 임의 메서드를 정의할 수 있음

but, 함수 컴포넌트도 Hooks라는 기능이 도입되면서 해결

 

 

3.2 첫 컴포넌트 생성

● 함수 컴포넌트

//MyComponent.js

const MyComponent = () => {
    return <div>나의 새롭고 멋진 컴포넌트</div>;
};

export default MyComponent; //다른 파일에서 이 파일을 import할 때, 위에서 선언한 MyComponent 클래스를 불러오도록 한다

() = > { } 화살표 함수 문법을 사용하여 함수를 만든다.

 

 

● 모듈 불러오기

App 컴포넌트에서 MyComponent 컴포넌트를 불러와서 사용한다

//App.js

import MyComponent from './MyComponent'; //MyComponent 컴포넌트를 불러온다

const App = () => {
  return <MyComponent />;

};

export default App;

 

 

3.3  props

props : 컴포넌트 속성을 설정할 때 사용하는 요소

 

● JSX 내부에서 props 렌더링

//MyComponent.js

const MyComponent = props => {
    return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>; //name이라는 props를 렌더링하도록 설정하였다
};

export default MyComponent;

 

● props 값 지정하기

//App.js

import MyComponent from './MyComponent';

const App = () => {
  return <MyComponent name="React" />;  //props값 지정
};

export default App;

 

● props 기본값 설정 : defaultProps

//MyComponent.js

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

MyComponent.defaultProps = {  //props 값을 따로 지정하지 않았을 때 보여 줄 기본값을 설정한다
    name: '기본 이름'
};

export default MyComponent;

 

● 태그 사이의 내용 보여줌 : children

//MyComponent.js

const MyComponent = props => {
    return (
        <div>
            안녕하세요, 제 이름은 {props.name}입니다. <br />
            children 값은 {props.children}  //태그 사이에 작성한 문자열을 MyComponent내부에서 보여준다
            입니다.
        </div>
    );
};

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

export default MyComponent;

 

● 비구조화 할당 문법

비구조화 할당 : 객체에서 값을 추출하는 문법

//MyComponent.js

const MyComponent = ({name, children}) => {  //비구조화 할당 문법을 사용하여 내부 값을 바로 추출한다
    return (
        <div>
            안녕하세요, 제 이름은 {name}입니다. <br />
            children 값은 {children}
            입니다.
        </div>
    );
};

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

export default MyComponent;

 

● propTypes

propTypes : props의 타입을 지정

//MyComponent.js
import PropTypes from 'prop-types';  //propTypes 사용

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

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

MyComponent.propTypes = {  
    name: PropTypes.string   //name 값은 무조건 문자열 형태로 전달해야 한다
};

export default MyComponent;

만약 propTypes에서 지정한 형태와 일치하지 않으면 Console 탭에서 오류를 발견할 수 있다

 

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

 

방법1 - render 함수에서 this.props 조회하기

//MyComponent.js
import { Component } from 'react';
import PropTypes from 'prop-types';  

class MyComponent extends Component {
    render() {
        const { name, favoriteNumber, children } = this.props;  //render함수에서 this.props를 조회한다
        return (
            <div>
                안녕하세요, 제 이름은 {name}입니다. <br />
                children 값을 {children}
                입니다.
                <br />
                제가 좋아하는 숫자는 {favoriteNumber}입니다.
            </div>
        );
    }
}

MyComponent.defaultProps = {    //함수형과 똑같은 방식
    name: '기본 이름'
};

MyComponent.propTypes = {      //함수형과 똑같은 방식
    name: PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired
};

export default MyComponent;

 

방법2 - class 내부에서 지정하기

//MyComponent.js
import { Component } from 'react';
import PropTypes from 'prop-types';  

class MyComponent extends Component {

    static defaultProps = {    //class 내부에서 지정한다
        name: '기본 이름'
    };
    static propTypes = {      //class 내부에서 지정한다
        name: PropTypes.string,
        favoriteNumber: PropTypes.number.isRequired
    };

    render() {
        const { name, favoriteNumber, children } = this.props;  //render함수에서 this.props를 조회한다
        return (
            <div>
                안녕하세요, 제 이름은 {name}입니다. <br />
                children 값을 {children}
                입니다.
                <br />
                제가 좋아하는 숫자는 {favoriteNumber}입니다.
            </div>
        );
    }
}


export default MyComponent;

 

 

 

3.4 state

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

 

● 종류

- 클래스형 컴포넌트가 지니고 있는 state

- 함수형 컴포넌트에서 useState를 통해 사용하는 state

 

● 클래스형 컴포넌트의 state

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

class Counter extends Component {
    constructor(props) {   //컴포넌트에 state를 설정할 때는 constructor 메서드를 작성한다
        super(props);   //state의 초깃값 설정하기, 반드시 작성!
        this.state = {
            number: 0   //초깃값 설정
        };
    }
    render() {
        const { number } = this.state;   //현재 state를 조회할 때 this.state로 조회한다
        return (
            <div>
                <h1>{number}</h1>
                <button
                // onClick로 버튼이 클릭되었을 때 호출할 함수를 지정한다
                    onClick={() => {
                        this.setState({ number: number + 1});  //this.setState를 사용하여 state에 새로운 값을 넣는다
                    }}
                >
                    +1
                </button>
            </div>
        );
    }
}

export default Counter;

만약 state안에 fixedNumber라는 값을 추가해주고 

this.setState에서 개체 내부에 fixedNumber를 넣어주지 않는다면 값이 바뀌지 않는다

 

● state를 constructor에서 꺼내기

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

class Counter extends Component {
    state = {    //state를 이용해 constructor에서 꺼냈다
        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>
        );
    }
}

export default Counter;

 

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

onClick에 설정한 함수 내부에서 this.setState를 두 번 호출하면

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

this.setState를 사용한다고 state 값이 바로 바뀌지 않기 때문에 1만 더해진다

                                                          ↓

this.setState를 사용할 때 객체 대신에 함수를 인자로 넣어준다 !!

 

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

class Counter extends Component {
    state = {    
        number: 0,
        fixedNumber: 0
    };
    
    render() {
        const { number, fixedNumber } = this.state;  
        return (
            <div>
                <h1>{number}</h1>
                <button
                    //onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정한다
                    onClick={() => {
                        this.setState(prevState => {
                            return {
                                number: prevState.number + 1
                            };
                        });
                        this.setState(prevState => ({   
                            number: prevState.number + 1
                        }));   //prevState => ({}) 형태를 이용하면 바로 객체를 반환한다
                    }}
                >
                    +1
                </button>
            </div>
        );
    }
}

export default Counter;

2가 더해진다

 

● 배열 비구조화 할당

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

                                                          ↓ 배열 비구조화 할당

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

 

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

//Say.js
import { useState } from 'react';

const Say = () => {
    const [message, setMessage] = useState('');    
    //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를 사용할 때 주의 사항

- state 값을 바꾸어야 할 때는

setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 한다.

 

- 배열이나 객체를 업데이트해야 할 때는

객체 사본을 만들고 사본에 값을 업데이트한 후, 사본의 상태를 setState 혹은 세터 함수를 통해 업데이트해야 한다.