developer Studying/React

[react] Props 낱낱이 파헤치기

ParkYeseul 2024. 9. 10. 14:06

오늘은 기분이 좋다. 

왜냐면 어제 진~ㅉㅏ 많이 먹었는데 먹고 누워서 책 읽고 핸드폰 하다 디비 자니까 행복했다.

먹고 싶었던 500kcal가 넘는 아주 맛있는 과자를 혼자 다 먹었다.

(마라탕, 밥 두공기, 제육볶음, 강된장, 온갖 쌈, 과자, 아이스크림 ...내 혈당은 누가 막아주지?)

그런데 오늘도 많이 먹을거라서 기분이가  좋다.

기운이 딸려서 먹고 힘 좀 내야겠어!

 

무튼 오늘 공부한 props를 정리해보겠다.

 

('초보자를 위한 리액트200제'를 통해 공부한 내용을 복기하는 시간입니다.

모든 내용과 코드는 위 책을 통해서 적었습니다!)

 

 


 

🧚‍♂️Props?

props는 부모 컴포넌트가 자식 컴포넌트에 데이터를 전달할 때 사용한다.
특이점은 props를 전달받은 자식 컴포넌트에서는 데이터 수정 X

그래서 데이터를 변경하려면 컴포넌트 내부에서만 사용하는 변수에 값을 넣어서 사용해야 한다.

 

 

위 말이 조금 어렵게 느껴졌고, 피부로 와닿지 않는다.

지피티에게 예시 코드를 받았다.

 

// 부모 컴포넌트에서 자식 컴포넌트에 name과 age를 전달
<ChildComponent name="John" age={30} />




// 자식 컴포넌트
function ChildComponent(props) {
    return <p>{props.name} is {props.age} years old.</p>;
}

//props는 부모가 전달해준 값을 단순히 읽고 표시하는 역할을 하며,
//자식 컴포넌트에서는 그 값을 변경할 수 없다. 
//만약 자식 컴포넌트에서 props를 변경해야 한다면, 
//부모 컴포넌트가 그 값을 변경한 뒤 다시 자식에게 전달해야 합니다.




//데이터를 변경하려면 컴포넌트 내부에서 사용하는 변수를 사용해야 한다.
//데이터를 수정하고 싶을 때는 컴포넌트 내부에서 state를 사용해야 한다. 
//state는 컴포넌트 내부에서 관리되는 데이터로, 해당 데이터를 변경하고 다시 렌더링

class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };  // 내부 상태 관리
    }

    incrementCount = () => {
        this.setState({ count: this.state.count + 1 });  // state 변경
    }

    render() {
        return (
            <div>
                <p>{this.props.name} has clicked {this.state.count} times.</p>
                <button onClick={this.incrementCount}>Increment</button>
            </div>
        );
    }
}

 

 

요약하자면,

props는 부모로부터 자식에게 데이터를 전달하는 용도이며, 자식 컴포넌트는 이 데이터를 수정할 수 없다.

데이터를 변경하고 싶다면, 컴포넌트 내부에서 state를 사용해 내부 데이터를 관리해라! 이 말씀!

 

 

 

🏌️‍♂️props에서 데이터 사용해보기

import { Component } from "react";


class R017_Props extends Component{
render(){
    let props_value = this.props.props_val;
    props_value += ' from App.js'
    return(
        <div>{props_value}</div>
    )
}
}

export default R017_Props;

여기서 신기했던 점은

this.props.뒤에 상위 컴포넌트(App.js)에서 전달받은 props변수명을 붙이면 해당 데이터를 쓸 수 있다.

`App.js 파일 <Props props_val="이것 프롭스다!"/>` => 그럼 화면에 이것 프롭스다! 라고 띄워진다. 

 

🏌️‍♂️props 자료형 선언

import { Component } from "react";
import datatype from 'prop-types';  // prop-types 라이브러리 임포트

// 클래스형 컴포넌트 정의
class R018_PropsDatatype extends Component {
    render() {
        // props에서 전달된 값을 구조분해 할당으로 추출
        //구조분해 할당을 사용하지 않으면, this.props로 모든 값을 참조해야 함
        let {
            String, Number, Boolean, Array, ObjectJson, Function
        } = this.props

        return (
            <div style={{padding: "0px"}}>  {/* 스타일 적용 */}
                {/* props로 전달된 String 값 출력 */}
                <p>StringProps: {String}</p>
                {/* props로 전달된 Number 값 출력 */}
                <p>NumberProps: {Number}</p>
                {/* props로 전달된 Boolean 값을 문자열로 변환 후 출력 */}
                <span>BooleanProps: {Boolean.toString()}</span>
                {/* props로 전달된 Array 값을 문자열로 변환 후 출력 */}
                <p>ArrayProps: {Array.toString()}</p>
                {/* props로 전달된 ObjectJson을 JSON 문자열로 변환 후 출력 */}
                <p>ObjectJsonProps: {JSON.stringify(ObjectJson)}</p>
                {/* props로 전달된 Function을 출력 */}
                <p>FunctionProps: {Function}</p>
            </div>
        )
    }
}

// propTypes를 이용해 props의 데이터 타입을 정의
R018_PropsDatatype.propTypes = {
    String: datatype.string,      // String은 문자열이어야 함
    Number: datatype.number,      // Number는 숫자여야 함
    Boolean: datatype.bool,       // Boolean은 불리언 타입이어야 함
    Array: datatype.array,        // Array는 배열이어야 함
    ObjectJson: datatype.object,  // ObjectJson은 객체여야 함
    Function: datatype.func       // Function은 함수여야 함
}

export default R018_PropsDatatype;  // 컴포넌트 내보내기

자식 컴포넌트에서 props에 대한 자료형을 선언해 놓으면,

부모 컴포넌트에서 넘어오는 props변수들의 자료형과 비교한다. 이때 자료형이 일치하지 않는다면, 경고 메시지로 알려주기에 잘못된 데이터를 파악하기 좋다.

 

처음에 let으로 구조분해 할당을 왜 하는지 궁금해서 찾아봤다.

let으로 구조분해 할당을 하지 않으면, props를 사용할 때마다 this.props.String, this.props.Number 등으로 참조해야 한다고 한다. 즉 단순화와 코드 가독성을 높이기 위함.

 

🏌️‍♂️props Boolean 사용하기

import { Component } from "react";
import datatype from 'prop-types';  // prop-types 라이브러리 임포트

// 클래스형 컴포넌트 정의
class R019_PropsBoolean extends Component {
    render() {
        // props에서 BooleanTrueFalse 값을 구조분해 할당으로 추출
        let {
            BooleanTrueFalse
        } = this.props;

        return (
            <div style={{padding: "0px"}}>  {/* 스타일 적용 */}
                {/* BooleanTrueFalse가 true일 때 '2.' 출력, false일 때 '1.' 출력 */}
                {BooleanTrueFalse ? '2.' : '1.'}
                {/* BooleanTrueFalse 값을 문자열로 변환 후 출력 */}
                {BooleanTrueFalse.toString()}
            </div>
        );
    }
}

export default R019_PropsBoolean;  // 컴포넌트 내보내기

 

props값을 Boolean형으로 하위 컴포넌트에 전달할 경우, true나 false 중 하나를 할당한다.

props 변수를 선언한 후 값을 할당하지 않고 넘기면 true가 기본값으로 할당된다.

 

그래서 BooleanTrueFalse 변수가 false일 경우 그대로 false가 출력되고,

값이 없을 경우 기본값으로 true가 화면에 출력된다.

Boolean 변수는 직접 화면에 출력할 수 없어서 tostring()함수를 사용해 문자열로 변환

 

 

🏌️‍♂️props 객체형으로 사용하기

import { Component } from "react";
import datatype from 'prop-types';  // prop-types 라이브러리 임포트

// 클래스형 컴포넌트 정의
class R020_PropsObjVal extends Component {
    render() {
        let {
            ObjectJson
        } = this.props

        return (
            <div style={{padding: "0px"}}>  {/* 스타일 적용 */}
            {JSON.stringify(ObjectJson)}
            </div>
        );
    }
}
R020_PropsObjVal.propTypes={
    
    ObjectJson: datatype.shape({
        react: datatype.string,
        twohundred: datatype.number
     })


}

export default R020_PropsObjVal;  // 컴포넌트 내보내기

props 값을 객체로 전달할 때, 자료형을 object로 선언한다.

하지만 객체 내부 변수들의 자료형을 선언할 때는 shape이라는 유형을 사용

 

🏌️‍♂️props를 기본값으로 정의하기

import { Component } from "react";

// 클래스형 컴포넌트 정의
class R022_PropsDefault extends Component {
    render() {
        // props에서 ReactString, ReactNumber 값을 구조분해 할당으로 추출
        let {
            ReactString,
            ReactNumber
        } = this.props;

        return (
            <div style={{padding: "0px"}}>  {/* 스타일 적용 */}
                {/* ReactString과 ReactNumber 값을 출력 */}
                {ReactString}{ReactNumber}
            </div>
        );
    }
}

// propTypes를 사용하여 prop의 데이터 타입을 지정하고, 필수 prop 설정
R022_PropsDefault.propTypes = {
    ReactString: "리액트", // ReactString은 필수이며, 문자열이어야 함
    ReactNumber: 400             // ReactNumber는 숫자 타입이어야 함 (선택 사항)
}

export default R022_PropsDefault;  // 컴포넌트 내보내기

props의 기본값은 부모 컴포넌트에서 값이 넘어 오지 않았을 때 사용.

그 때! defaultProps라는 문법을 사용한다.

app.js에서는 ReactNumber={200} 값을 전달했다.

위 코드를 보면 ReactString, ReactNumber 변수에 각각 기본값을 할당한 상태

 

ReactString 변숫값은 비어 있어서  ReactString: "리액트"로 지정한 기본값이 화면에 출력

반면 ReactNumber는 상위컴포넌트에서 {200}이라는 값이 전달됐기 때문에 400이란 값은 무시된다.

 

 

 


 

 

 

👨‍💻정리해볼게! 얍!

이 예시들로 리액트 기본 로직들이 이해가 되기 시작했다.

오늘 개발자 관련 책을 읽으면서 하나 깨달은 점이 있다.

 

<모든 코드는 존재 이유가 있으며, 그 코드들이 만들어졌을 때는 분명한 의도를 가지고

만들어졌다. >

 

나는 한 번도 이 코드가 왜 생겼을지 생각을 해본적이 없다.

그냥 익숙하게 사용했을 뿐.

 

그렇지만 이 코드가 언제 어떻게 쓰이는 지 명확하게 알고 사용한다면, 

코드를 짜는 데 있어서 더 효율적으로 일을 할 수 있지 않을까?

삐약이 개발자니까 더욱 기반을 탄탄하게 하고 싶다.

 

그럴려면 내가 제일 잘하고 싶은 언어를 골라서 좀 깊게 세세하게 파본다면,

다음 최신 언어를 만나도 무섭지 않지 않을까?

(라틴어에서 영어가 파생된 것처럼..) 개발 언어도 파생 되는 게 많으니까!

 

아무튼 조금 귀찮고 하기 싫어도 꼭 필요한 과정이라고 생각하고 해야겠다!

 

'developer Studying > React' 카테고리의 다른 글

[react] Component와 Component의 라이프 사이클(Lifecycle)  (2) 2024.09.09
[react]Map()함수  (3) 2024.09.06