ReduxのサンプルのTodoリストを真似てみる。Part.4の続きです。
前回のサンプルに、redux-undoでUndo/Redo機能をつける
0.留意点
- 前回の記事から、Reduxのサンプル "todos-with-undo"とおなじ機能を付けてみた。
- 初心者の覚書です。
- 自分の環境で動くように参考にしたコードを適当に修正している。
- Windows10 64bit , PowerShellなどで動かしている。
- 見栄えを若干よくする為にbootstrap4を利用している。
- 前回から、見やすくするため、bootstrapの設定や、DOMの表示上の並びを変更してある
- redux-undo 関係だけを記述する
1.redux-undoのインストール
redux-undoのGitHubにあるように、素直にしたがう。
npm install --save redux-undo@beta
はじめ、@beta をつけずにインストールしたが、いろいろ具合が悪かった。
reducersをredux-undo対応にする。
もともとの todosリデューサーをundoableでラップする。
これで
state.todos.past
state.todos.present
state.todos.future
などが使えるようになる。
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の第二引数を関数にして、エラーがでた。仕様上、関数をうける場合、オブジェクトを受ける場合の2通りあるようだが、こっちはオブジェクトらしい。
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コンテナを追加
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;
実行結果
ReduxのサンプルのTodoリストを真似てみる。Part.5 https://t.co/D8s5VS06DN @YouTubeさんから
— tkarasuma (@tkarasuma) 2018年6月1日
補足
reducers\visibilityFilter.js にフィルターのりデューサもあり、todosと同様にundo/redoに組み込んでみたが、todosと干渉してか、不審な挙動をするので外した。