끄적끄적

[REACT] Presentational 컴포넌트와 Container 컴포넌트 본문

Front-end/React.js

[REACT] Presentational 컴포넌트와 Container 컴포넌트

mashko 2021. 4. 26. 23:15
반응형

프레젠테이셔널 컴포넌트와 컨테이너 컴포넌트
리액트를 이용해 개발을 하고 계신 분들이라면 대부분 이미 알고 계실껍니다.
이번 글을 통해 프레젠테이셔널 컴포넌트와 컨테이너 컴포넌트의 개념에 대해 정리해보고자 합니다.

프레젠테이션 컴포넌트

1. 직접적으로 보여지는 부분에 대해 담당한다.
2. Store에 의존적이지 않다.
3. props를 통해 데이터와 callback을 전달 받는다.
4. 마크업과 스타일을 가진다.
5. 데이터를 직접적으로 변경하지 않는다.
6. UI 상태값 이외에 대체로 다른 상태값을 가지고 있지 않는다.

컨테이너 컴포넌트

1. 데이터 핸들링에 대한 위주로 개발한다.
2. 마크업이나 스타일을 가지지 않는다.
3. 리덕스의 액션이나 상태 변경에 대한 로직을 담고 있고, 프레젠테이셔널 컴포넌트에 해당 상태를 전달하거나 함수를 제공한다.
4. 다른 프레젠테이셔널 컴포넌트나 컨테이너 컴포넌트를 관리한다.

이렇게 각자의 용도가 명확하게 정리되어 분리하고, 대규모 프로젝트에서의 리소스 관리를 조금 더 수월하게 해줍니다.
데이터의 공급자와 뷰의 공급자를 나누어 상태나 비지니스로직에 대한 디펜던시를 제거해 주어 유지보수에 대해 편의를 제공합니다.
쉽게 말하면 UI와 DATA핸들링 부분에 대한 분리로 재사용성을 높여주는 겁니다.

예제

- 프레젠테이셔널 컴포넌트

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

import { Button } from 'antd';


const defaultProps = {
    number: -1,
    onPlus: createWarning('onPlus'),
    onSubtract: createWarning('onSubtract')
};

const propTypes = {
    number: PropTypes.number,
    onPlus: PropTypes.func,
    onSubtract: PropTypes.func
};



function createWarning(funcName) {
    return () => console.warn(funcName + ' is not defined');
}


const Counter = (props) => {
    return (
        <div>
            <h1>{ props.number }</h1>
            <Button type="primary" onClick={ props.onPlus }>+</Button>
            <Button type="primary" onClick={ props.onSubtract }>-</Button>
        </div>
    );
}

Counter.propTypes = propTypes;
Counter.defaultProps = defaultProps;

export default Counter;


- 컨테이너 컴포넌트

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

// UI Components
import Counter from 'components/StoreExample/Counter';

// Actions
import * as counterActions from 'stores/modules/example/counter.module';

class CounterContainer extends Component {

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <Counter
                    number={number}
                    onPlus={CounterActions.increment}
                    onSubtract={CounterActions.decrement}
                />
            </div>
        );
    }
}


const mapStateToProps = (state) => {
    return {
        number: state.counter.number
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        CounterActions: bindActionCreators(counterActions, dispatch)
    };
};

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(CounterContainer);

예제와 같이 두 컴포넌트는 명확하게 역활이 분담되어 있고, 이렇게 분리된 프레젠테이셔널 컴포넌트와 컨테이너 컴포넌트는 따로 여러가지 곳에서 재사용이 용이하게 됩니다.
해당 패턴은 리덕스를 개발한 Dan Abramov가 고안한 패턴입니다.
medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

반응형

'Front-end > React.js' 카테고리의 다른 글

[REACT] Redux란?  (0) 2021.05.05
[REACT] CRA를 통한 리액트 프로젝트 세팅하기  (0) 2021.04.01
[REACT] React Hooks 란?  (0) 2021.03.15
Comments