[TIL] React #2

24164 단어 TILReactReact

공부할 책 : Doit! 리액트 프로그래밍 정석

앞에서 ES6을 공부했다!
ES6 문법은 여름방학때도 다뤄봐서 사용할 땐 별 어려움 없을 것 같다!

문제는 내 의지와 귀차니즘뿐

리액트 컴포넌트

컴포넌트를 표현하는 JSX

JSX는 JavaScript XML의 줄임말로 자바스크립트에 XML을 추가한 확장형 문법이다. XML 또한 HTML의 표현법을 확장한 문법이므로 자바스크립트와 HTML 을 안다면 JSX도 쉽게 이해할 수 있다.

App.js

import React from 'react';

class App extends React.Component{
  render(){
    return (
      <div>
        <img src="http://www.easyspub.co.kr/images/logo_footer.png"/>
      </div>
    )
  }
}
export default App;

return() 함수 내에 HTML을 사용했다는 점을 알 수 있다.
HTML 과 거의 비슷하지만, JSX는 XML 마크업 규칙을 따른다. img 엘리먼트 끝에 마침 표시 />가 있다는 차이점이 있다.

index.js 파일은 yarn start 명령어로 리액트 서버를 구동했을 때 최초로 실행된다. 여기서 App.js 를 실행한다.

index.js

// 필수 리액트 구동 모듈들
import React from 'react';
import ReactDOM from 'react-dom';
// 초기 화면을 구성하는 사용자 코드
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

만약 App 컴포넌트를 사용하지 않는다면 index.js를 이렇게 수정해야 한다.

var img = document.createElement('img');
img.setAttribute('src', 'http://www.easyspub.co.kr/images/logo_footer.png');
var divEl = document.createElement('div');
divEl.innerText = '안녕하세요';
var welcomeEl = document.createElement('div');
welcomeEl.append(img);
welcomeEl.append(divEl);

var root = document.getElementById('root');
root.append(welcomeEl);

넘나 불편한것.. 리액트는 신이다

컴포넌트와 구성 요소

컴포넌트는 리액트의 꽃이라 불릴 정도로 리액트에서 가장 중요한 요소이다. 리액트로 작성된 화면은 컴포넌트만으로 구성되어 있기 때문이다.

컴포넌트의 개념

컴포넌트의 개념을 정확히 이해하기 위해 기존의 웹 프레임워크가 어떻게 동작하는지 간단히 알아보자면, 기존 웹 프레임워크는 MVC 방식으로 정보, 화면, 구동 코드를 분리하여 관리했다. 정보 담당을 모델(Model), 화면 담당을 뷰(View), 구동 담당을 컨트롤러(Controller)라고 부르는 것에서 MVC 라는 용어가 나왔다. 이 방식은 코드 관리를 효율적으로 할 수 있다는 장점이 있으나 MVC 각 요소의 의존성이 높아(하나만 바꾸기가 쉽지 않음) 재활용이 어렵다.

하지만 웹 사이트의 화면은 각 요소가 비슷하고 반복적으로 사용한 경우가 많다. 이 점을 착안하여 컴포넌트가 등장하게 된 것이다. 컴포넌트는 MVC의 뷰를 독립적으로 구성하여 재사용 할 수 있고, 컴포넌트를 통해 새로운 컴포넌트를 쉽게 만들 수 있다. 다양한 모양의 블록을 조립한다고 상상하면 된다.

컴포넌트 구성 요소

컴포넌트 주요 구성 요소는 다음과 같다. 구성 요소와 특징을 알아두고 넘어가자.

프로퍼티 : 상위 컴포넌트에서 하위 컴포넌트로 전달되는 읽기 전용 데이터이다.
state : 컴포넌트의 상태를 저장하고 변경할 수 있는 데이터이다.
컨텍스트 : 부모 컴포넌트에서 생성하여 모든 자식 컴포넌트에 전달하는 데이터이다.

프로퍼티

프로퍼티는 상위 컴포넌트가 하위 컴포넌트에 값을 전달할 때 사용한다. 이때 프로퍼티 값은 수정할 수 없다는 특징이 있다.

프로퍼티에서는 자바스크립트의 자료형을 모두 사용할 수 있다. 이때 프로퍼티의 자료형은 미리 선언해주는 것이 좋다. 프로퍼티의 자료형을 미리 선언하면 리액트 엔진이 프로퍼티로 전달하는 값의 변화를 효율적으로 감지할 수 있고, 개발자가 실수로 지정되지 않은 자료형을 프로퍼티에 전달하려고 할 때 경고 메세지로 알려주기 때문이다.

문자열형 프로퍼티

PropsComponent.jsx

import React from 'react';
import PropTypes from 'prop-types'; // prop-types 라이브러리를 PropTypes라는 이름으로 임포트

class PropsComponent extends React.Component{
    render(){
        return (
            <div className="message-container">
                {this.props.name} // name 프로퍼티로 받은 문자열 출력
            </div>
        )
    }
}

// 자료형을 선언하는 예제
PropsComponent.propTypes = { // PropsComponent의 propTypes라는 특수 변수(prop-types 라이브러리와는 다름)을 사용하여 프로퍼티의 자료형 정의
    name: PropTypes.string, // 프로퍼티의 자료형을 객체 형태로 지정하여 PropsComponent.propTypes에 저장
}

export default PropsComponent;

App.js

import React from 'react';
import PropsComponent from './03/PropsComponent';
class App extends React.Component{
  render(){
    return (
      <PropsComponent
        name="두잇 리액트"
      />
    )
  }
}
export default App;

프로퍼티에 문자열을 전달할 때는 큰따음표를 사용하는 것을 확인하자.

다양한 프로퍼티 사용하기

숫자형이나 불리언 등의 값을 전달할 때는 큰따옴표를 사용할 수 없다. 리액트에서 문자열 외의 값은 따옴표 대신 중괄호({})를 사용한다.

ChildComponent.jsx :

import React from 'react';
import PropTypes from 'prop-types';

class ChildComponent extends React.Component {

    render(){
    
        // 객체 구조 분해 할당식을 사용하여 프로퍼티에 전달된 값을을 render() 함수 내의 지역 변수로 재정의
        const {
            boolValue,
            numValue,
            arrayValue,
            objValue,
            nodeValue,
            funcValue,
        } = this.props;

        return(
            <div>
                <span>불리언값 : {boolValue}</span>
                <span>숫자값 : {numValue}</span>
                <span>배열값 : {arrayValue}</span>
                <span>객체값 : {String(objValue)}</span>
                <span>노드값 : {nodeValue}</span>
                <span>함수값 : {String(funcValue)}</span>
            </div>
        )
    }
}

ChildComponent.propTypes = {
    boolValue:PropTypes.bool,
    numValue:PropTypes.number,
    arrayValue:PropTypes.arrayOf(PropTypes.number),
    objValue:PropTypes.object,
    nodeValue:PropTypes.node,
    funcValue:PropTypes.func,
}

export default ChildComponent;

객체 구조 분해 할당식을 사용하여 프로퍼티에 전달된 값들을 함수 내의 지역 변수로 재정의했다. 이렇게 하면 this.props.boolValue에서 boolValue와 같이 this.props를 제외하는 방법으로 프로퍼티에 간단히 접근할 수 있다. 또한 이 방법은 일종의 '프로퍼티 목록' 의 역할을 하므로 개발을 할 때 참고하기도 좋다. 앞으로 이 방법을 자주 사용하자.

App 컴포넌트 :

import React from 'react';
import ChildComponent from './03/ChildComponent';

class App extends React.Component{
  render(){
    const array = [1,2,3];
    const obj = {name:'제목',age:30};
    const node = <h1>노드</h1>;
    const func =() => {console.log('메시지');}
    return (
      <ChildComponent
        boolValue={true}
        numValue={1}
        arrayValue={array}
        objValue={obj}
        nodeValue={node}
        funcValue={func}
      />
    )
  }
}
export default App;

불리언 프로퍼티 사용하기

불리언은 true 또는 false만 정의할 수 있는 특수한 자료형이다. 불리언값은 특별한 방법으로 전달할 수 있다. true의 경우 프로퍼티의 이름만 선언해도 전달할 수 있다.

<ChildComponent boolValue /> true를 불리언 프로퍼티에 전달
<ChildComponent /> false를 불리언 프로퍼티에 전달

다음은 프로퍼티에 true를 전달 한 예제이다.

BooleanComponent.jsx

import React from 'react';

class BooleanComponent extends React.Component {
    render() {
        const message = this.props.bored ? '놀러 가자' : '하던 일 열심히 마무리하기';
        return (
            <div className="message-container">
                {message}
            </div>
        )
    }
}

export default BooleanComponent;

App.jsx

import React from 'react';
import BooleanComponent from './03/BooleanComponent';

class App extends React.Component{
  render(){
    const array = [1,2,3];
    const obj = {name:'제목',age:30};
    const node = <h1>노드</h1>;
    const func =() => {console.log('메시지');}
    return (
      <div>
        <div><b>지루할 때 : </b><BooleanComponent bored/></div>
        <div><b>즐거울 때 : </b><BooleanComponent/></div>
      </div>
    )
  }
}
export default App;

실무에서 자주 사용하므로 꼭! 알아두자!

객체형 프로퍼티

ChildComponent2.jsx :

import React from 'react';
import PropTypes from 'prop-types';

class ChildComponent2 extends React.Component {
    render(){
        const {
            objValue,
        } = this.props;

        return (
            <div>
                <div>객체값 : {String(Object.entries(objValue))}</div>
            </div>
        )
    }
}

ChildComponent2.propTypes = {
    objValue:PropTypes.shape({
        name:PropTypes.string,
        age:PropTypes.number,
    })
}

export default ChildComponent2;

필수 프로퍼티

ChildComponent2.jsx :

import React from 'react';
import PropTypes from 'prop-types';

class ChildComponent2 extends React.Component {
    render(){
        const {
            objValue,
            requiredStringValue,
        } = this.props;

        return (
            <div>
                <div>객체값 : {String(Object.entries(objValue))}</div>
                <div>필수값 : {requiredStringValue}</div>
            </div>
        )
    }
}

ChildComponent2.propTypes = {
    //객체 프로퍼티
    objValue:PropTypes.shape({
        name:PropTypes.string,
        age:PropTypes.number,
    }),
    //필수 프로퍼티
    requiredStringValue: PropTypes.string.isRequired,
}

export default ChildComponent2;

App.js :

import React from 'react';
import ChildComponent2 from './03/ChildComponent2';

class App extends React.Component{
  render(){
    return (
      <div>
        <ChildComponent2
          objValue={{age:'10살'}}
        />
      </div>
    )
  }
}
export default App;

실행 결과 :

첫 번째 경고 메시지는 age에 문자열을 대입해서 나타난 것이고,
두 번째 경고 메시지는 필수 프로퍼티에 값을 지정하지 않았기 때문이다.

수정한 App.js 코드 :

import React from 'react';
import ChildComponent2 from './03/ChildComponent2';

class App extends React.Component{
  render(){
    return (
      <div>
        <ChildComponent2
          objValue={{age:10}}
          requiredStringValue="문자"
        />
      </div>
    )
  }
}
export default App;

프로퍼티 기본값 지정하기

만약 프로퍼티에 기본값을 지정하고 싶다면
기본값을 지정할 컴포넌트의 defaultProps값을 이용하면 된다.

DefaultPropComponent.jsx :

import React from 'react';
import PropTypes from 'prop-types';

class DefaultPropsComponent extends React.Component {
    render(){
        let message1 = '';
        if(this.props.boolValue===false){
            message1 = 'boolValue 기본값이 false입니다.';
        }
        let message2 = '';
        if(this.props.boolValueWithoutDefault === false){
            message2 = 'boolValueWithoudtDefault 기본값이 false입니다.';
        }
        return (
            <div className="message-container">
                {message1}
                {message2}
            </div>
        )
    }
}
DefaultPropsComponent.propTypes = {
    boolValue:PropTypes.bool,
    boolValueWithoutDefault:PropTypes.bool,
}
DefaultPropsComponent.defaultProps={
    boolValue : false,
};

export default DefaultPropsComponent;

App.jsx :

import React from 'react';
import DefaultPropsComponent from './03/DefaultPropsComponent';

class App extends React.Component{
  render(){
    return (
      <div>
        <DefaultPropsComponent/>
      </div>
    )
  }
}
export default App;

결과 :

자식 프로퍼티

App.jsx :

import React from 'react';
import ChildProperty from './03/ChildProperty';

class App extends React.Component{
  render(){
    return (
      <div>
        <ChildProperty>
          <div><span>자식 노드</span></div>
        </ChildProperty>
      </div>
    )
  }
}
export default App;

ChildProperty 컴포넌트에서는 {this.props.children} 과 같은 방법으로
<div><span>자식 노드</div></span>을 쉽게 받을 수 있다.

ChildProperty.jsx :

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

class ChildProperty extends Component {
    render(){
        return <div>{this.props.children}</div>;
    }
}
ChildProperty.propTypes = {
    children:PropTypes.node,
};
export default ChildProperty;

결과 :

좋은 웹페이지 즐겨찾기