Redux入門 (React.js)


React.jsでアプリケーションを開発するときに使われる「Redux」の入門記事です。


🐡 Reduxとは

React.jsが扱うUIのstate(状態)を管理するためのフレームワークです。React.jsで複雑なアプリケーションを作るとstateの変更箇所が複数に分散(componetが複数箇所で保持)して、管理が困難になるのを解決するためです。

🎉 Reduxの要素

Action

  • Actionは「何をする」という情報をもつオブジェクトです
  • Actionstore.dispatch()でstoreへ送られます
  • 文字列のtypeプロパティを必ず持ちます
const ADD_TODO = 'ADD_TODO'
{
type: ADD_TODO,
text: 'Input user message 1'
}

ActionCreator

ActionCreatorActionを生成するメソッドです。

function addTodo(text) {
return {
type: ADD_TODO,
text
}
}

dispatchするときはcreatorで作成したactionを渡します。

dispatch(addTodo(text))

もしくはdispatchまでを行うcreatorを準備する方法もあります。

const boundAddTodo = (text) => dispatch(addTodo(text));
const boundCompleteTodo = (index) => dispatch(completeTodo(index));

reduxのbindActionCreators()を使う方法もあるようです。

import { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
let boundActionCreators = bindActionCreators(TodoActionCreators, dispatch)

Store

Storeはアプリケーションの状態(state)を保持する場所です。Storeの役割は次のとおりです。

  • stateを保持する
  • getState()メソッドでstateにアクセスを許可する
  • dispatch(action)メソッドでstateを更新する
  • subscribe(listener)メソッドでリスナーを登録できる

todoのサンプルのstateは次のようになります。

{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Input user message 1',
completed: false,
},
{
text: 'Past user message 0',
completed: false,
},
]
}

Storeには次のルールがあります。

  • アプリケーション内でStoreは1つのみとし、Stateは単独のオブジェクトとしてStoreに保持する必要があります
  • stateを直接変更することはせず、Storeへdispatchすることでしかstateは変更できません

Reducer

  • ReducerActionstateから「新しいstate」を返すメソッドです
  • Actiontypeプロパティに応じて処理を書く必要があります
  • 生成された「新しいstate」はstoreに保持されます
  • stateにはUIの内容を入れないようにするのが推奨されます
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case COMPLETE_TODO:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
]
default:
return state
}
}
function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}

Reducerには次のルールがあります。

  • Reducerは現在のstateactionを受けて新しいstateを返すだけの純粋なメソッドとします
  • 引数の値を変更したり、APIを呼び出すような副作用が発生すること、毎回値が変わることはNG

🚌 よく使うAPI

Provider

Providerの目的は次の2つです。

  • Reactコンポーネント内でreact-reduxのconnectを使えるようにすること
  • ラップしたコンポーネントにstore情報を渡すこと

connect

ReduxのStoreがReactにアクセスするための関数。

サンプルコード

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from "redux";
import { Provider } from "react-redux";
import App from './App';
ReactDOM.render(
<Provider store={ store }>
<App />
</Provider>,
document.getElementById('root')
);
// App.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
doSomething(e) {
// do something
}
render() {
const { app: { count } } = this.props;
return (
<div className="App">
<div className="App-header">
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<button onClick={this.doSomething}>hoge</button>
</div>
);
}
}
function mapStateToProps(state) {
return { app: state.app };
}
export default connect(mapStateToProps)(App);

🐯 参考リンク

📚 おすすめの書籍

🖥 サーバについて

このブログでは「Cloud Garage」さんのDev Assist Program(開発者向けインスタンス無償提供制度)でお借りしたサーバで技術検証しています。 Dev Assist Programは、開発者や開発コミュニティ、スタートアップ企業の方が1GBメモリのインスタンス3台を1年間無料で借りれる心強い制度です!(有償でも1,480円/月と格安)