Suzuki Blog Written by Yuki Suzuki

Reduxの基本的な使い方【Reactアプリで状態管理をする】

React

先日Reactでアプリを作成しました。

Minimum Options

駅名、料理のジャンル、個室の有無、支払い方法を選択し、お店の検索ができるグルメアプリです。

駅名などの入力内容を保存する際にReduxを使用しています。

今回はこのアプリを用いて、Reduxの基本的な使い方をまとめます。

記事の内容

  • Reduxとは
  • 導入
  • state
  • Action
  • Reducer
  • Store
  • mapStateToProps
  • mapDispatchToProps
  • Storeにアクセスする

スポンサードサーチ

Reduxとは

Reduxはアプリの状態を管理するためのライブラリです。

Angularなどと併用できますが、Reactと使用するのが最も相性がいいようです。

導入

今回のアプリではReactと使用しています。

以下のコマンドを実行することで、ReactとReduxを連携することができます。

npm install redux
npm install react-redux

スポンサードサーチ

state

アプリの状態を表します。

今回のアプリでは「入力された駅名」「選択されたジャンル」をstateとして管理します。

Action

Actionとは「何をする」という情報を持ったオブジェクトです。

例えば「駅名を入力した」「ジャンルを選択した」といった情報のことです。

またActionでは必ずtypeプロパティを持ちます。

このtypeプロパティがActionの種類を示します。

export const SEND_STATION = 'SEND_STATION';
export const SEND_GENRE = 'SEND_GENRE';
export const SEND_FEELING = 'SEND_FEELING';
export const SEND_SEAT = 'SEND_SEAT';
export const SEND_PAYMENT = 'SEND_PAYMENT';

export const sendStation = station => ({
    type: SEND_STATION,
    station,
})

export const sendGenre = genre => ({
    type: SEND_GENRE,
    genre,
})

export const sendSeat = seat => ({
    type: SEND_SEAT,
    seat,
})

export const sendPayment = payment => ({
    type: SEND_PAYMENT,
    payment,
})

スポンサードサーチ

Reducer

ReducerはActionとstateを元に、新しいstateを作成するメソッドです。

「駅名が入力されたら、駅名を更新する」というイメージです。

ReducerはActionのtypeに応じて、処理を書きます。

import {SEND_STATION} from '../action'

const initialAppState = {
  station: '',
};

const stationreducer = (state = initialAppState, action) => {
  // typeに応じて処理を書く
  if (action.type === SEND_STATION) {
    return Object.assign({}, state, {
      station: action.station
    });
  } else {
    return state;
  }
};

export default stationreducer;

今回のアプリのように管理するstateが複数ある場合、stateごとに子Reducerを用意し、親Reducerでまとめて管理することができます。(RootReducerを作成できる)

その場合はcombineReducersを利用します。

import { combineReducers } from 'redux';
import station from './stationreducer';
import genre from './genrereducer';
import seat from './seatreducer';
import payment from './paymentreducer';

// RootReducers作成、ここに子Reducerを追加する
const reducer = combineReducers({
  station,
  genre,
  seat,
  payment
});

export default reducer;

Store

Storeはstateを保持している場所です。

アプリ内にStoreは1つだけです。

StoreはcreateStore()で作成します。

combineReducersで作成したRootReducerを渡すことで作成できます。

import React from 'react';
import ReactDOM from 'react-dom';
import './scss/index.scss';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './reducers/index';

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

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

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

スポンサードサーチ

mapStateToProps

mapStateToPropsはStoreのstateをpropsに詰め込むための関数です。

この関数によってstateの値をアプリ内で扱うことができるようになります。(画面に表示するなど)

mapDispatchToProps

mapDispatchToPropsはActionをDispatch(送信)するための関数です。

この関数によって、「入力された駅名で、stateを更新する」ことができるようになります。

この2つの関数の定義ができたら、connect()の引数に渡せばOKです。

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import Header from './header';
import { connect } from 'react-redux';
import * as actions from '../action';

class station extends Component {

    constructor(props) {
        super(props);
        this.state = {
            station: '恵比寿',
        }
        this.handleChange = this.handleChange.bind(this)
        this.handleClick = this.handleClick.bind(this)
    }

    handleChange(e) {
        this.setState({
            station: e.target.value
        })
    }

    handleClick() {
        this.props.onClick(this.state.station);
        this.props.history.push("/genre");
    }

    render() {
        return (
            <>
                <Header />
                <div className={'search'}>
                    <p className={'search-text'}>
                        地名などのキーワードを入力してください。<br />
                        半角スペース区切りで複数入力できます。
                    </p>
                    <input className={'search-textBox'} type='text' value={this.state.station} onChange={this.handleChange}></input>
                    <button className={'search-button'} onClick={this.handleClick}>次へ</button>
                </div>
            </>
        );
    }
}

// propsにstateの値を詰め込む(取得する)
const mapStateToProps = (state) => ({
    station: state.station.station,
});

// actionをdispatchする(更新する)
function mapDispatchToProps(dispatch) {
    return {
        onClick(station) {
            dispatch(actions.sendStation(station));
        }
    };
}

// connect()の引数に定義した関数を渡す
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(station));

Storeにアクセスする

Storeにアクセスするには、Providerというコンポーネントを使います。

作成したStoreをProviderに渡すことでStoreを利用できるようになります。

import React from 'react';
import ReactDOM from 'react-dom';
import './scss/index.scss';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './reducers/index';

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

// Providerを使ってStoreにアクセスする
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

まとめ

以上がReactとReduxの基本的な使い方です。

Reduxを使うことでアプリの状態管理ができるようになります。

ぜひアプリ開発に取り入れてみてください。

参考

React + Redux の基本的な使い方

Redux入門【ダイジェスト版】10分で理解するReduxの基礎

webエンジニア転職を目指している方はこちら

webエンジニア転職のロードマップ