ReduxのサンプルのTodoリストを真似てみる。Part.5

[ReduxのサンプルのTodoリストを真似てみる。Part.4](https://qiita.com/tkarasuma/items/80af44a93a8990db0dfa)の続きです。
前回のサンプルに、redux-undoでUndo/Redo機能をつける

#0.留意点
- 前回の記事から、Reduxのサンプル "todos-with-undo"とおなじ機能を付けてみた。
- 初心者の覚書です。
- 自分の環境で動くように参考にしたコードを適当に修正している。
- Windows10 64bit , PowerShellなどで動かしている。
- 見栄えを若干よくする為にbootstrap4を利用している。
- 前回から、見やすくするため、bootstrapの設定や、DOMの表示上の並びを変更してある
- redux-undo 関係だけを記述する

#1.redux-undoのインストール

[redux-undoのGitHub](https://github.com/omnidan/redux-undo)にあるように、素直にしたがう。

```PowerShell:PowerShellコンソール
npm install --save redux-undo@beta
```
はじめ、**@beta** をつけずにインストールしたが、いろいろ具合が悪かった。

##reducersをredux-undo対応にする。

もともとの　todosリデューサーをundoableでラップする。
これで

state.todos.past
state.todos.present
state.todos.future

などが使えるようになる。

```javascript:reducers\todo.js
import undoable, { includeAction } from 'redux-undo';

const todos = (state = [], action) => {
    switch (action.type) {
        case 'ADD_TODO':
            return [...state,
            {
                id: action.id,
                text: action.text,
                completed: false
            }
            ]
        case 'TOGGLE_TODO':
            return state.map(
                (todo) => {
                    if (action.id !== todo.id) {
                        return todo;
                    } else {
                        return  Object.assign({},todo,{completed:!todo.completed});
                    }
                }
            );
        default:
            return state;
    }
}

const undoableTodos = undoable(todos, { filter: includeAction(['ADD_TODO', 'TOGGLE_TODO']) });
export default undoableTodos;
```

##UndoRedoコンテナをつくる

UndoRedoコンポーネントをconnectでラップ。

mapDispatchToProps がオブジェクトであることに注意。
connectの第二引数を関数にして、エラーがでた。仕様上、関数をうける場合、オブジェクトを受ける場合の２通りあるようだが、こっちはオブジェクトらしい。


```jsx:containers\UndoRedo.js
import React from 'react';
import { connect } from 'react-redux';
import { ActionCreators as UndoActionCreators, ActionCreators } from 'redux-undo';

let UndoRedo = ({ canUndo, canRedo, onUndo, onRedo }) => (
    <div className="mb-1">
        <button className="btn btn-info mr-3" onClick={onUndo} disabled={!canUndo}>元に戻す</button>
        <button className="btn btn-info" onClick={onRedo} disabled={!canRedo}>やり直す</button>
    </div>
)

const mapStateToProps = (state) => {
    return {
        canUndo: state.todos.past.length > 0,
        canRedo: state.todos.future.length > 0
    }
}

const mapDispatchToProps = {
    onUndo: UndoActionCreators.undo,
    onRedo: UndoActionCreators.redo
}

UndoRedo = connect(mapStateToProps, mapDispatchToProps)(UndoRedo);

export default UndoRedo;
```
##AppコンポーネントにUndoRedoコンテナを追加

```jsx:components\App.js
import React from 'react';
import VisibleTodoList from '../containers/VisibleTodoList';
import AddTodo from '../containers/AddTodo';
import Footer from "./Footer";
import UndoRedo from "../containers/UndoRedo";

//classNameでBootsrapに関する設定
const App = () => (
    <div>
        <h1 className="text-center alert alert-info ">Todoリスト</h1>
        <UndoRedo />
        <Footer />
        <VisibleTodoList />
        <AddTodo />
    </div>
)

export default App;
```

##実行結果

<blockquote class="twitter-tweet" data-cards="hidden" data-lang="ja"><p lang="ja" dir="ltr">ReduxのサンプルのTodoリストを真似てみる。Part.5 <a href="https://t.co/D8s5VS06DN">https://t.co/D8s5VS06DN</a> <a href="https://twitter.com/YouTube?ref_src=twsrc%5Etfw">@YouTube</a>さんから</p>&mdash; tkarasuma (@tkarasuma) <a href="https://twitter.com/tkarasuma/status/1002377235376979968?ref_src=twsrc%5Etfw">2018年6月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[ソースコード 09](https://github.com/tkarasuma/JavaScript/tree/master/ws_09)

##補足

reducers\visibilityFilter.js　にフィルターのりデューサもあり、todosと同様にundo/redoに組み込んでみたが、todosと干渉してか、不審な挙動をするので外した。