5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

カウントアプリを作ってReduxの流れを理解する。

Last updated at Posted at 2019-06-17

カウントアプリの概要

スクリーンショット 2019-06-17 12.00.51.png 増えたり減ったりします。

Reactのみでこのアプリを実装。

Reactのみでカウントアプリを作成して、後からReduxを導入します。
create-react-appでReactアプリを作成してある程で話が進みます

# ディレクトリ構造

react-app/
        ├  node_modules
        ├  public
        ├  src
        │   ├ components
        │   │      ├ App.js
        │   │
        │   ├ index.js
        ├  package.json
        ├  README.md
        ├  yarn.lock

表示部分の実装

src/components/App.js
import React , { Component } from 'react'; // Componentをimportする
class App extends Component{
  render(){
    return(
      <React.Fragment>
        <div>count : 0</div>
        <button>+1</button>
        <button>-1</button>
      </React.Fragment>
    )
  }
}

export default App;

class componentを使って実装していくので、importしておく。

App.jsをcomponents配下に移動させたので、src/index.jsも変更する。

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App'; //ここを変更

ReactDOM.render(<App />, document.getElementById('root'));

これで、動かないが画面への表示される。

次にボタンを押すと、stateが更新され、countの数字が変わるようにしていく。

src/components/App.js

import React , { Component } from 'react';

class App extends Component{

  constructor(props){
    super(props)
    this.state = { count: 0 } //countの初期値を設定
  }

  // プラスボタンが押された時の処理
  handlePlusButton = () => {
    this.setState({ count: this.state.count + 1})
  }

  // マイナスボタンが押された時の処理
  handleMinusButton = () => {
    this.setState({ count: this.state.count - 1})
  }

  render(){
    return(
      <React.Fragment>
        <div>count : { this.state.count }</div>
        <button onClick={this.handlePlusButton}>+1</button> 
        <button onClick={this.handleMinusButton}>-1</button>
      </React.Fragment>
    )
  }
}

export default App;

Reactのみのカウントアプリはこれで完成。

Reduxの導入

Reduxを利用するためにパッケージをinstallする。

yarn add react react-redux

ディレクトリ構造を変更する。

react-app/
        ├  node_modules
        ├  public
        ├  src
        │   ├ components
        │   │      ├ App.js
        │   │
        │   ├ actions 
        │   │      ├ index.js 
        │   │
        │   ├ reducers
        │   │      ├ index.js
        │   │      ├ count.js
        │   │
        │   ├ utils
        │   │      ├ index.js
        │   │
        │   ├ index.js
        ├  package.json
        ├  README.md
        ├  yarn.lock

アクション(actions)の作成

アクションには、アプリケーション内部で起こる出来事を記載する。jsのオブジェクトで処理は書かない。
オブジェクト内部には、ユニークな名前を持つ'type'キーと、typeに対応する値を持つ。

src/actions/index.js

export const INCREMENT = 'INCREMENT'  //再利用することが多いので定義。あとでutils/indexに移動します。
export const DECREMENT = 'DECREMENT'  //再利用することが多いので定義。あとでutils/indexに移動します。

//プラスする処理の名前
export const increment = () =>({
    type: INCREMENT
  })

//マイナスする処理の名前
export const decrement = () =>({
    type: DECREMENT
  })

ここで、utils/index.jsを作成して、上記のINCREMENTとDECREMENTを定義して、src/actions/index.jsからimportする仕組みにする。

src/utils/index.js

export const INCREMENT = 'INCREMENT'  
export const DECREMENT = 'DECREMENT'  
src/actions/index.js

import { INCREMENT, DECREMENT } from './utils' //ここを追加

//プラスする処理の名前
export const increment = () =>({
    type: INCREMENT
  })

//マイナスする処理の名前
export const decrement = () =>({
    type: DECREMENT
  })

reducerの作成

actionが発生した時に、そのactionのtypeに応じて、stateをどう変化させるのか定義する。

src/reducers/index.js

// 全てのreducerをまとめるためのファイル
import { combineReducers } from 'redux' //applicationの全reducerをまとめるために必要
import count from './count'

export default combineReducers({ count })
// export default combineReducers({ count, hoge, huga }) のように書く。これで、count,hoge,hugaが使えるようになる。
src/reducers/count.js

import { INCREMENT, DECREMENT } from '../utils'

const initialState = { value: 0 } //状態の初期値を定義。

const count = (state = initialState, action) => {
  switch(action.type){
    case INCREMENT:
      return {value: state.value + 1} //変更したい状態を返す。※ここではまだ状態は変わっていない。
    case DECREMENT:
      return {value: state.value - 1}
    default:
      return state
  }
}

export default count;

Storeの作成

アプリケーションの状態(state)を保持する。

src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux' //storeを作成するために必要
import { Provider } from 'react-redux' //作成したstoreを全componentに渡すために必要

import App from './components/App';
import reducer from './reducers' //作成したreducerをimportしておく

const store = createStore(reducer) //storeの作成

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

これで、redux部分はほとんど完成。

ReactとReduxのつなぎこみ

src/components/App.js

import React, { Component } from 'react';
import { connect } from 'react-redux'
import { increment, decrement } from '../actions' //actionsのimport


class App extends Component{
  render(){
    const props = this.props //状態やアクションを渡す。mapStateToPropsで定義されている。関数はmapDipatchTopropsで渡されている。
    return(
        <React.Fragment>
        <div>count : { props.value }</div>
        <button onClick={props.increment}>+1</button>
        <button onClick={props.decrement}>-1</button>
        </React.Fragment>

    )
  }
}

// stateの情報からこのcomponentで必要なものを取り出してcomponent内のpropsとしてマッピング機能
// 引数には、状態のトップレベルを示すstateを書いて、どういったオブジェクトをpropsとして対応させるのか、関数の戻り値として定義。
const mapStateToProps = (state) =>{
  return {value: state.count.value}
}

//あるアクションが発生した時に、reducerにタイプに応じた状態遷移を実行させるための関数がdipatche。
//このdispatch関数を引数に置くことで、このcomponentで必要になるdipatche関数を宣言する。
const mapDispatchToProps = (dispatch) =>(
  {
    increment: () => dispatch(increment()),
    decrement: () => dispatch(decrement())
  }
)


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

ここでつまづいたのが、

const props = this.props

これは、mapStateToPropsとmapDispatchToPropsでそれぞれから状態を受け取っていた。
なので、今回だと、valueとincrement関数、decrement関数が渡されている。

まとめ

ソースコード
https://github.com/satokiyoshino/react-count-app
compileエラーが起きないで、バグが起きるとデバッグがめちゃくちゃ難しい。
Chromeの拡張で、Redux Devtoolがあるので、これを使えば少し助かるかもしれない。
https://github.com/zalmoxisus/redux-devtools-extension

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?