안 쓰던 블로그

React-컴포넌트(컴포넌트 생성, props, state) 본문

Web/React

React-컴포넌트(컴포넌트 생성, props, state)

proqk 2020. 7. 6. 18:33
반응형

리액트를 사용하여 애플리케이션 인터페이스를 설계할 때, 사용자가 볼 수 있는 요소를 여러 가지 컴포넌트로 분리한다

각 기능을 맡은 컴포넌트를 만들고 파일을 따로따로 저장하여 모든 뷰를 다른 파일로 분리하는 식이다

이렇게 컴포넌트를 쓴다면 단순한 템플릿 이상의 효율을 갖을 수 있다

예를 들어 데이터가 주어졌을 때 이에 맞추어 UI를 만들어주거나, LifeCycle API를 이용하여 컴포넌트가 화면에서 나타나고 사라질 때 주어진 작업을 처리할 수 있고, 메서드를 만들어 특별한 기능 붙이기도 가능하다

 

컴포넌트 생성

생성하기

vscode에서 scr디렉토리 마우스 오른쪽 클릭-새 파일-MyComponent.js 입력

그리고 코드 작성

import React, { Component } from 'react';

class MyComponent extends Component {
    render() {
        return (
            <div>
                나의 새롭고 짱멋진 컴포넌트
            </div>
        );
    }
}

export default MyComponent;

 

모듈 내보내기

맨 아래쪽 코드를 보면

export default MyComponent;

이런 게 있음

이 코드는 다른 파일에서 이 파일을 import할 때, 위쪽에서 선언한 MyComponent 클래스를 불러오도록 설정한다

 

모듈 불러오기

App.js에서 MyComponent 모듈을 불러온다

import React, {Component, Fragment} from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  render(){
    return(
      <MyComponent/>
    );
  }
}

export default App;

 

 

렌더링 결과

 

props

properties의 줄임말로 컴포넌트 속성을 설정할 때 사용하는 요소

props값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서만 설정할 수 있다(여기서는 App.js)

 

1. JSX 내부에서 props 렌더링

import React, { Component } from 'react';

class MyComponent extends Component {
    render() {
        return (
            <div>
                {this.props.name}의 새롭고 짱멋진 컴포넌트
            </div>
        );
    }
}

export default MyComponent;

MyCompoenet.js 파일을 수정해서 name이라는 props를 렌더링하도록 설정했다

props를 렌더링 할 때는 JSX 내부에서 {}안에 감싸주면 된다

접근할 때는 this 키워드를 사용한다

 

2. 컴포넌트 사용할 때 props 값 설정

import React, {Component} from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  render(){
    return(
      <MyComponent name="proqk" />
    );
  }
}

export default App;

 

HTML태그에 속성을 설정하는 것과 비슷하다

 

결과

+. 디폴트 값 지정하기

값이 없을 때 그냥 출력하지 않고 디폴트 값을 넣는다

import React, { Component } from 'react';

class MyComponent extends Component {
    render() {
        return (
            <div>
                {this.props.name} 의 새롭고 짱멋진 컴포넌트
            </div>
        );
    }
}

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

export default MyComponent;

MyComponent.js 수정

 

import React, {Component} from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  render(){
    return(
      //<MyComponent name="proqk" />
      <MyComponent />
    );
  }
}

export default App;

App.js 수정

 

 

아니면 이렇게도 된다

차이점은 없다

import React, { Component } from 'react';

class MyComponent extends Component {
    static defaultProps={
        name: '기본이름'
    }
    render() {
        return (
            <div>
                {this.props.name} 의 새롭고 짱멋진 컴포넌트
            </div>
        );
    }
}

export default MyComponent;

 

props 검증: propTypes

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

import PropTypes from 'prop-types';

MyComponent.js에서 불러온다

 

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class MyComponent extends Component {
    static defaultProps={
        name: '기본이름'
    }
    static propTypes={
        name: PropTypes.string
    }
    render() {
        return (
            <div>
                {this.props.name} 의 새롭고 짱멋진 컴포넌트
            </div>
        );
    }
}

export default MyComponent;

기본 타입을 string으로 설정한다

이것도 아까처럼 클래스 밖에다가 선언할 수 있다

 

App.js의 MyComponent 사용 부분을 다음과 같이 바꾼다

<MyComponent name="proqk" />

참고로 문자열 종류 외의 값을 컴포넌트에 전달할 때는 {}로 감싸야 한다

숫자면 {3} 이런 식

 

필수 propTypes 설정

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class MyComponent extends Component {
    static defaultProps={
        name: '기본이름'
    }
    static propTypes={
        name: PropTypes.string,
        age: PropTypes.number.isRequired
    }
    render() {
        return (
            <div>
                {this.props.name}의 새롭고 짱멋진 컴포넌트
                저는 {this.props.age}살 입니다
            </div>
        );
    }
}

export default MyComponent;

MyComponent.js를 이렇게 수정한다

age는 숫자 타입으로 필수로 지정한다는 의미다

 

import React, {Component} from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  render(){
    return(
      <MyComponent name="proqk" age={19}/>
    );
  }
}

export default App;

App.js를 수정

 

19살 여고생쟝 proqk입니다

 

여기서 이상한 에러가 난다면? 참고- https://foxtrotin.tistory.com/215

 

propTypes 종류

array 배열

bool 참거짓

func 함수

number 숫자

object 객체

string 문자열

symbol 심볼 객체

node 렌더링할 수 있는 모든 것(숫자, 문자열, element등)

element 리액트 요소

instanceOf 특정 클래스의 인스턴스

any 아무거나

 

등등

 

state

props는 부모 컴포넌트가 설정하고, 컴포넌트 자신은 해당  props를 읽기 전용으로만 사용할 수 있다

컴포넌트 내부에서 읽고 업데이트할 수 있는 값을 사용하려면 state를 써야 한다

기본 값을 미리 설정해야만 사용 가능하고, this.setState() 메서드로만 값을 얻을 수 있다

 

1. 컴포넌트 생성자 메서드 constructor()

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class MyComponent extends Component {
    static defaultProps={
        name: '기본이름'
    }
    static propTypes={
        name: PropTypes.string,
        age: PropTypes.number.isRequired
    }

    constructor(props){
        super(props);
    }
    
    render() {
        return (
            <div>
                <p>{this.props.name}의 새롭고 짱멋진 컴포넌트</p>
                <p>저는 {this.props.age}살 입니다</p>
            </div>
        );
    }
}

export default MyComponent;

메서드 내부에서 부모 클래스인 Component의 constructor메서드를 먼저 호출해야하므로 super 키워드 사용

컴포넌트를 만들 때 props 값들을 사용해야 해서 props를 메서드 파라미터로 전달한다

 

2. 초깃값 설정

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

 

3. JSX내부에서 state 렌더링

    render() {
        return (
            <div>
                <p>{this.props.name}의 새롭고 짱멋진 컴포넌트</p>
                <p>저는 {this.props.age}살 입니다</p>
                <p>숫자: {this.state.number}</p>
            </div>
        );
    }

MyComponent.js에서 여기까지 수정한다

그러면 값 0을 렌더링한다

4. state값 업데이트: setState()

    render() {
        return (
            <div>
                <p>{this.props.name}의 새롭고 짱멋진 컴포넌트</p>
                <p>저는 {this.props.age}살 입니다</p>
                <p>숫자: {this.state.number}</p>
                <button onClick={()=>{
                    this.setState({
                        number: this.state.number+1
                    })
                }
            }>더하기</button>
            </div>
        );
    }

버튼을 누를 때마다 숫자가 1씩 증가한다

여기서 사용한 이벤트 시스템은 다음 글에서 자세하게 다뤄보았다

 

*ES6의 화살표 함수-함수를 파라미터로 전달할 때 사용한다

 

5.  state를 constructor에서 꺼내기

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class MyComponent extends Component {
    static defaultProps={
        name: '기본이름'
    }
    static propTypes={
        name: PropTypes.string,
        age: PropTypes.number.isRequired
    }

    state={
        number:0
    }
    
    render() {
        return (
            <div>
                <p>{this.props.name}의 새롭고 짱멋진 컴포넌트</p>
                <p>저는 {this.props.age}살 입니다</p>
                <p>숫자: {this.state.number}</p>
                <button onClick={()=>{
                    this.setState({
                        number: this.state.number+1
                    })
                }
            }>더하기</button>
            </div>
        );
    }
}

export default MyComponent;

원래 초기 state는 constructor 메서드에서 정의해야 하지만,

defaultProps와 propTypes를 정의할 때 사용한 transform-class-properties 문법으로 constructor바깥에서 정의할 수 있다

위에 state={}가 그렇게 정의한 형태이다

 

값 업데이트 시 주의할 점

this.state.number = this.state.number + 1;
this.state.someObject.value = 3;
this.state.someArray.push(3);

state값을 업데이트 할 때는 무조건 .setState()를 사용해야 한다

위의 코드처럼 직접 접근하면 안 된다

왜냐하면 이렇게 직접 접근하면 컴포넌트를 자동으로 리렌더링하지 않기 때문이다

(물론 this.forceUpdate()로 강제 렌더링을 할 수 있지만 비효율적이다)

그래서 배열이나 객체를 업데이트할 때는 배열/객체 사본을 만들고 그 사본에 값을 업데이트해서 다시 사본을 넘기는 방식으로 한다

 

반응형
Comments