今回はreact-reduxのdocksというデザインパターンを使って簡単なメモ帳アプリを作っていきます。
超簡単(一言で)にreact, redux, docksの説明します。
- react
- redux
- docks:
- react-redux
今回はtodoリストよりシンプルな以下のようなアプリを作っていきます。
各種インストール
まずnode jsがインストールされている
次にReactプロジェクトのテンプレートを作成する
npx create-react-app react-redux-app
ReduxをReactで使うためのライブラリのインストール
npm install --save react-redux
(エラーでひっかかったらsudo付けてみてください)
実装
moduleの作成
docksではaction_type,action_creater,reducer をmoduleという単位で扱います。
今回はメモに関するaction_type,action_creater,reducerをここにいれます。
では、moduleを作っていきます。
ディレクトリを作成します。
mkdir module && cd module
moduleの中に
let nextMemoId = 0; // action const ADD_MEMO = 'ADD_MEMO'; //action creator export const actionCreaters = { addMemo: text => ({ type: 'ADD_MEMO', id: nextMemoId++, text, }), }; // reducer export default function reducer(state = [], action) { switch (action.type) { case ADD_MEMO: return [ ...state, { id: action.id, text: action.text, completed: false, }, ]; default: return state; } }
action_createrでは, actionの名前やactionに必要な情報が格納されている
オブジェクトを生成します。
reducerは受け取ったstateとactionを使って新しいstateを生成します。
reducerはdispatchされた場合にその処理を行います。
次にmodule/index.jsを以下のように作ります。
import memoReducer from './memo'; export default { memo: memoReducer, };
をつくります。
module/index.jsを作ることによって
外部からmoduleをimportする場合にindex.jsにexportされたモジュールを取得します。
containers, compornentsの作成
次にcontainersとcompornentsを作成します。
まずはディレクトリを作成しておきます。
mkdir src/containers mkdir src/compornents
ファイルをどんどん書いていきます。
(ちなみにデフォルトではsrc/App.jsとなっていますが消すか、このディレクトリに移動してください)
src/compornents/App.js
import React, { Component } from 'react'; import '../App.css'; import AddMemo from '../containers/AddMemo'; import VisibleMemoList from '../containers/VisibleMemoList'; class App extends Component { render() { return (); } } export default App
srs/compornents/Form.js
import React from 'react'; import Button from '@material-ui/core/Button'; export default class Form extends React.Component { render() { return ( <form className="addMemo" onSubmit={e => { e.preventDefault(); if (!this.refs.inputText.value.trim()) { return; } this.props.addMemo(this.refs.inputText.value); this.refs.inputText.value = ''; }} > <input type="type" className="addMemo_input" ref="inputText" /> <Button variant="contained" color="primary" style={{ marginLeft: '20px' }} onClick={() => this.props.addMemo(this.refs.inputText.value)} > 追加 </Button> </form> ); } }
srs/compornents/Memo.js
import React from 'react'; import Card from '@material-ui/core/Card'; export default class Memo extends React.Component { render() { return (); } } {this.props.text}
srs/compornents/MemoList.js
import React from 'react'; import Memo from './Memo'; import Card from '@material-ui/core/Card'; export default class MemoList extends React.Component { render() { console.log('MemoList'); console.log(this.props); return ( <Card className="memoList"> <h2 className="memoList_title">TODO</h2> <div className="notCompleted"> {this.props.memos.map(memo => ( <Memo key={memo.id} toggleMemo={this.props.toggleMemo} {...memo} /> ))} </div> </Card> ); } }
containersも同様に
import { connect } from 'react-redux'; import { actionCreaters } from '../modules/memo'; import Form from '../components/Form'; const mapDispatchToProps = dispatch => { return { addMemo: text => dispatch(actionCreaters.addMemo(text)), }; }; export default connect(null, mapDispatchToProps)(Form);
src/containers/VisibleMemoList.js
import { connect } from 'react-redux'; import memoListModule from '../modules/memo'; import MemoList from '../components/MemoList'; const mapStateToProps = state => { console.log('mapStateToProps'); console.log(state); return { memos: state.memo, }; }; const mapDispatchToProps = dispatch => { return { toggleMemo: id => dispatch(memoListModule.toggleMemo(id)), }; }; export default connect(mapStateToProps, mapDispatchToProps)(MemoList);
最後にsrc/index.js
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './components/App'; import * as serviceWorker from './serviceWorker'; import { createStore, combineReducers } from 'redux'; import { Provider } from 'react-redux'; import reducer from './modules'; console.log(reducer); const store = createStore( combineReducers({ ...reducer, }) ); console.log(store); console.log(store.getState()); ReactDOM.render(, document.getElementById('root') ); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister();