본문 바로가기

FrontEnd/React,Redux

PART3:Simply build App with Redux - Mock, webpack_loaders, Component

MocApi

지난 포스팅에서의 내용들은 LOAD_BOARD_CLEAR action 을 통해서 데이터를

호출하기 위함 이였다.

오늘은 더미 데이터를 호출하고 테이블 형태로 게시글을 셋팅 하는 내용을

구현하고자 한다.

먼저 MockApi 를 만든다.

api 폴더에 boardApi.js 를 생성 하고 Promise 를 이용해 클래스를 구현한다.

해당 Mock data는 최근 스터디 주제였던 자바스크립트 자료구조와 알고리즘 Data Structures & Algorithms with JavaScript 이책의 아마존 서평을 긁어와서 사용했다.

boardApi.js

const contents = [
{
    id: "1",
    title: "Careless Mistakes",
    content: "This is very disappointing. I have had the book for about 3 hours now and I have noticed several mistakes",
    author:"Pat J Ryll",
    date:"2014/04/13"

},
{
    id:"2",
    title:"Hindered by many, many mistakes",
    content:"The explanation is good and the exercises are helpful but I've found several critical mistakes in the first few chapters alone",
    author:"Joshua Cunningham",
    date:"2014/06/03"
},
{
    id:"3",
    title:"like CS 101 with JS",
    content:"Mike McMillan's 'Data Structures and Algorithms with JavaScript' uses JavaScript as a vehicle for introducing a number of fundamental computer science concepts",
    author:"R. Friesel Jr.",
    date:"2014/03/30"
},
{
    id:"4",
    title:"Incomplete",
    content:"This book has no proofcoding. The examples and exercises rely on unfinished code. Call in sick to work, you'll need an entire day to code all the missing bits and pieces.",
    author:"Audioeye",
    date:"2015/03/30"
}
]

export default class boardApi {
    static getAllContents() {
            return new Promise((resolve, reject) => {
                resolve(Object.assign([], contents));
            });
    }
}

Bootstrap

Bootstrap 을 이용해서 테이블형태 게시판 레이아웃을 구성할것 이다.

웹팩에 로더를 통해 Bootstrap 을 호출 하는 방식을 사용한다.

다소 어려울수 있는데 이부분을 건너 뛰고 싶다면

dist 폴더에 있는 index.html 에 head 부분에

link 태그로 부트스트랩을 추가해서 사용하면된다.

웹팩 로더 방식 설명을 이어가겟다.

코딩에 앞서 src 최상단에 있는 index.js 에 다음 코드를 추가 한다.

import '../node_modules/bootstrap/dist/css/bootstrap.min.css';

부트 스트랩 뿐만 아니라 css도 이와같은 방식으로 로드해서 사용할수 있는데

아직 필요한 로더와 설정이 되지 않았기때문에 작동은 되지 않을것이다.

style-loader,css-loader,url-loader,file-loader 웹팩 로더가 필요하다.

npm i -D style-loader css-loader url-loader file-loader

개발 의존성으로 설치하고 난뒤에 webpack.config.js 파일에 로더를 수정한다.

추가한 코드 라는 주석이 있는곳 이하 코드를 전부 추가 한다.

 module: {
            loaders: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader',
                    query: {
                        presets:['es2015', 'react']
                    }
                },
                /*추가한 코드*/
                {
                    test: /(\.css)$/,
                    loaders: ['style', 'css']
                },
                {
                    test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
                    loader: 'file'
                },
                {
                    test: /\.(woff|woff2)$/,
                    loader: 'url?prefix=font/&limit=5000'
                },
                {
                    test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
                    loader: 'url?limit=10000&mimetype=application/octet-stream'
                },
                {
                    test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
                    loader: 'url?limit=10000&mimetype=image/svg+xml'
                }
            ]
        }

웹팩을 통해 정상적으로 로드되는것이 확인될것이다.

style.css 도 추가 해보자.

Action define

처음 포스팅 글에서 actions 폴더에 생성한 boardActions.js 파일을 기억할 것이다.

더미 데이터를 불러올 MockApi가 있기때문에 Action를 구현한다.

boardActions.js

import { LOAD_BOARD_CLEAR } from './actionTypes'; import boardApi from '../api/boardApi'; export function loadBoard() { return (dispatch) => { return boardApi.getAllContents() .then(contents => dispatch({type : LOAD_BOARD_CLEAR, contents })) .catch(error => { throw(error); }); } };

게시판에 더미 데이터는 초기에 셋팅되어야 한다

리액트의 컴포넌트 라이프사이클 메소드인 componentDidMount 를 활용해도 되고

store에 dispatch 해줘도 된다.

필자는 store에 dispatch 를 해줬다.

index.js 코드를 추가한다.

index.js

import 'babel-polyfill';
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import configureStore from './store/store';
import { loadBoard } from './actions/boardActions'; //추가
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';

const store = configureStore();
store.dispatch(loadBoard()); //추가 

render(
    <Provider store={store} >
        <Router history={browserHistory} routes={routes} />
    </Provider>,document.getElementById("root"));

이제 About.js 컴포넌트를 작성해보자.

Component

기존에 class 를 export 했던 컴포넌트와는 차이가 있다.

오늘 포스팅에서는 이해를 돕기 위해 smart dumb 컴포넌트를 나누지 않고

About.js 페이지에 모두 구현했지만 기능 추가를 하면서 분리하기로 하고

이페이지에서 핵심은 connect 이다.

connect 는 react-redux 내장함수로 이함수가 하는 역할은 Redux store에

해당 컴포넌트를 연결해주는 역할을 한다.

인수로 mapStateToProps 와 mapDispathProps 를 받는데

mapStateToProps 는 store 의 state 를 컴포넌트 props 에 매핑 시켜주는 역할을 한다.

mapDispatchProps 는 컴포넌트의 특정 함수형 props 를 실행 했을 때

지정한 action을 dispatch 하도록 설정한다.

두 인수 모두 ownProps 를 명시할수 있는데 이를 통해 함수 내부에서 컴포넌트의

props 값에 접근하게 해준다.

게시판 기능을 추가하면서 다뤄볼 기회가 있기때문에 지금은 connect 중심으로 코드만 봐두자.

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as boardActions from '../../actions/boardActions'

class About extends Component {
    constructor(props, context) {
        super(props, context);

    }

    render() {
        const contents = this.props.contents;

        return (
            <div>
                <table className="table table-hover table-striped">
                    <thead>
                        <tr>
                            <th>No</th>
                            <th>Title</th>
                            <th>Author</th>
                            <th>Date</th>
                        </tr>
                    </thead>
                    <tbody>
                        {contents.map(content =>
                            <tr key={content.id}>
                                <td>{content.id}</td>
                                <td>{content.title}</td>
                                <td>{content.author}</td>
                                <td>{content.date}</td>
                            </tr>
                                )}
                    </tbody>
                </table>
            </div>
            )
    }
}

About.propTypes = {
    contents: PropTypes.array.isRequired,
    actions: PropTypes.object.isRequired
}

function mapStateToProps(state, ownProps) {
    return {
        contents: state.contents
    };
}

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators(boardActions, dispatch)
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(About)

그리고 약간에 스타일을 추가한다.

#root {
    font: 14px 'Hevetica Neue', Hevetica, Arial, sans-serif;
    color: #4d4d4d;
    min-width: 550px;
    max-width: 850px;
    margin: 0 auto;
}

a {
    text-decoration: none;
    font-weight: bold;
}
a.active {
    color: orange;

}


nav {
    padding: 10px 0 10px 0;
    box-sizing: content-box;
}

필자는 style 폴더를 만들어서 style.css 파일을 생성했다.

그리고 index.js 에 추가해줬다.

import './style/style.css';

여기까지 왔다면 이제 화면을 볼수 있다.

 

다음 포스팅에서는 더미 데이터의 여정을 통해서 본 Redux 의 흐름을

리마인드 해보려 한다.