理論そっちのけで、とりあえず簡単なアプリを作ってみます。
今回作るもの
なんてことのない、ただのカウントアプリです↓
注意点
ただ模写していく事で「あ、なんとなく書けるかも」と思えることが目的です。
理論などの説明は下記リンク群が大変参考になりました。
全くつかめていない方は、これらを見てから書いてみるとわかりやすいと思います。
開発環境
カテゴリ | バージョン |
---|---|
OS | macOS Mojave 10.14.4 |
Node.js | 10.15.3 |
Yarn | 1.13.0 |
React | 16.8.6 |
Redux | 4.0.1 |
模写の準備
開発環境の構築
Node.js, Yarnのインストール
ここの説明は省略します。
わからない人は、このQiitaが懇切丁寧です。
create-react-appのインストール
Facebook社が作ってくださった「create-react-app」という雛形をダウンロードします。
$ yarn global add create-react-app
※"./path/to/applciation"の部分で作成するアプリケーションへのパスを指定
$ create-react-app ./path/to/application
このような、React自身やその他諸々のライブラリをまとめて、雛形を作成してくれるツールを「boilerplate」と言います。
色々な種類がありますので、気になる方はこちらを参考に。
実際に雛形が作成され、下記のようなフォルダ・ファイル群が生成されます↓
.
├── README.md
├── node_modules
├── package.json
├── public
├── src
└── yarn.lock
とりあえず起動してみましょう。Reactのロゴがブラウザで表示されれば成功です。
$ yarn start
Redux, react-reduxのインストール
ちなみにreact-reduxはReactとReduxの仲介役を担っているモジュールです。
$ yarn add redux react-redux
これで開発環境は構築できました。
ファイル構成を整える
src
ディレクトリの配下をこんな感じにしておきましょう。
あらかじめフォルダやファイルを作っていくことで、模写がラクになります。
├── App.css
├── App.test.js
├── actions
│ └── index.js
├── components
│ └── App.js
├── index.js
├── reducers
│ ├── count.js
│ └── index.js
└── serviceWorker.js
レッツ模写!
Actionの定義
storeにメッセージを送るためのActionを定義します。
カウントアプリは「+」と「-」ボタンによって状態を変化させるだけですので、必要なアクションは2つのみとなります。
export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'
// 書き方が2通りありますが、どちらでも問題ないです
export const increment = () => {
return {
type: INCREMENT
}
}
export const decrement = () => ({
type: DECREMENT
)}
Reducerの実装
storeから送られた情報をもとにstateを実際に変更する「Reducer」を実装しましょう。
index.jsの実装
Reducer群を管理するindex.js
を実装します。
今回作成するアプリは1つのReducerしか持たないので、count.jsと分離する必要はありません。
ただ、規模の大きいアプリの場合は必要となりますので、今後の為にもやっておきましょう。
import { combineReducers } from 'redux'
import count from './count'
export default combineReducers(({ count }))
count.jsの実装
カウンターの数字を変更する部分となります。
storeから送られる情報の中のaction.type
によって、数字を増やすのか・減らすのかを決めています。
import { INCREMENT, DECREMENT } from '../actions'
//コンポーネントの初期値を設定
const initialState = { value: 0 }
export default (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return { value: state.value + 1 }
case DECREMENT:
return { value: state.value - 1 }
default:
return state
}
}
storeの実装
実装されたReducerをもとに、storeを作成します。
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './reducers'
import App from './components'
import * as serviceWorker from './serviceWorker'
// 作成されたReducerをもとにstoreを作成
// アプリケーション内部の全てのstateは、このstateに集約される
const store = createStore(reducer)
// Providerによって、storeがどのコンポーネントからも参照できるようになる
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
コンポーネントの実装
index.js
で呼び出している「App」コンポーネントを実装しましょう。
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { increment, decrement } from '../actions'
class App extends Component {
render() {
const props = this.props
return (
<React.Fragment>
<div>count:{props.value}</div>
<button onClick={props.increment}>+</button>
<button onClick={props.decrement}>-</button>
</React.Fragment>
);
}
}
// stateから必要な情報をコンポーネントにマッピングする関数
const mapStateToProps = state => ({ value: state.count.value })
// dispatch関数をコンポーネントにマッピングする関数
const mapDispatchToProps = dispatch => ({
increment: () => dispatch(increment()),
decrement: () => dispatch(decrement())
})
// こんな書き方もある↓
// const mapDispatchToProps = ({ increment, decrement })
// stateとacitonをコンポーネントに関連づける
export default connect(mapStateToProps, mapDispatchToProps)(App)
次は...
TODOリストや、Ajax通信を実装してみるといいかもしれません。