【React実験】 Reduxテンプレート(非同期対応)

非同期対応のReact x Reduxテンプレート(自分用)を作成したのでメモを残しておく。

ディレクトリ構成

ROOT_DIR/
  + node_modules/
  + build/
  + source/
      + scripts/
      |   + components/
      |   |   + app/
      |   |       + component.jsx
      |   |       + styles.js
      |   |       + actions.js
      |   |       + container.js
      |   |       + reducer.js
      |   |
      |   + reducer.js
      |   + renderer.js
      |   + main.js
      |
      + index.html

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Redux Tutorial</title>
</head>
<body>
  <div id="app"></div>

  <script src="./scripts/main.js"></script>
</body>
</html>

scripts/main.js

import renderer from "./renderer";

scripts/renderer.js

非同期用のミドルウェア react-thunk を利用する。

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunkMiddleware from "redux-thunk";
import reducer from "./reducer";
import App from "./components/app/container";

let store = createStore(reducer, applyMiddleware(
  thunkMiddleware
));

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("app")
);

scripts/reducer.js

import { combineReducers } from "redux";
import appReducer from "./components/app/reducer";

export default combineReducers({
  "app": appReducer
});

scripts/components/app/component.jsx

CSS in JSを使用してスタイリングを行う。

CSS in JS と CSS Modules // Speaker Deck

import React from "react";
import styles from "./styles";

export default class App extends React.Component {
  render() {
    return (
      <div>
        <p style={styles.count}>
          {this.props.count}
        </p>

        <p>
          <button onClick={this.props.handleClick}>
            Click!
          </button>
        </p>
      </div>
    );
  }
}

scripts/components/app/styles.js

CSS in JSではスタイルをキャメルケースで記述する。

export default {
  "count": {
    "fontSize": "24px"
  }
};

scripts/components/app/actions.js

redux-thunk ミドルウェアを使用するため、Actionを関数で返すことができる。これにより関数内の好きなタイミングでActionを dispatch することができる。

通常通りオブジェクト形式で返すこともできる。

export default {
  "increment": () => {
    return dispatch => {
      dispatch({
        "type": "INCREMENT"
      });
    };
  }
};

scripts/components/app/container.js

import React from "react";
import { connect } from "react-redux";
import Component from "./component";
import Actions from "./actions";

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

function mapStateToProps(state) {
  return state.app;
}

function mapDispatchToProps(dispatch) {
  return {
    "handleClick": () => {
      dispatch(Actions.increment());
    }
  };
}

scripts/components/app/reducer.js

let initialState = {
  "count": 0
};

export default function reducer(state = initialState, action) {
  switch(action.type) {
    case "INCREMENT":
      return Object.assign({}, state, {
        "count": state.count + 1
      });

    default:
      return state;
  }
}