#概要
前回の記事ではTodoアプリにTodoを追加する『Add Todo』機能を実装しました。今回は、追加されたTodoをクリックした際に斜線を引けるようにし、Todoの未・済を判別出来る機能を実装したいと思います!
前回の記事
React + ReduxでTodoアプリを作ってみよう!『Add Todo編』
#completed属性を付与する
completed属性を付与することで、Todoが完了済みなのか未完了なのかを判別できるようにしましょう!Todoを追加する際にcompleted属性にfalseをデフォルトとして設定します!
import {ADD_TODO, TOGGLE_TODO} from '../actions';
const todos = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return [...state, {id: action.id, text: action.text, completed: false}];
default:
return state;
}
};
export default todos;
#completed属性によってTodoのstyleを変更する
completedの属性がtrueかfalseかによってTodoに斜線を引けるようにstyleを反映させましょう!
import React from 'react';
import PropTypes from 'prop-types';
const Todo = ({onClick, completed, text}) => {
return (
<li style={{textDecoration: completed ? 'line-through' : 'none'}}>
{text}
</li>
);
};
Todo.propTypes = {
completed: PropTypes.bool.isRequired,
text: PropTypes.string.isRequired,
};
export default Todo;
#Action経由でcompleted属性を操作する
Action経由でcompleted属性を操作するために、まずはAction Creatorを作成しましょう。横線を引くTodoを判別するために、idを取得します。
export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO';
let nextTodoId = 0;
export const addTodo = text => {
return {
type: ADD_TODO,
id: nextTodoId++,
text,
//text: text,
};
};
export const toggleTodo = id => {
return {
type: TOGGLE_TODO,
id,
//id: id
};
};
またreducersに戻りaction.type
がTOGGLE_TODO
の際の状態遷移の方法を記述しましょう。この中では、stateに保管されているTodoのidと横線を引きたいTodoのidを比較し、お互いに一致するようであれば、一致したidのTodoが持っているcompleted属性を逆転させます。
import {ADD_TODO, TOGGLE_TODO} from '../actions';
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 =>
todo.id === action.id ? {...todo, completed: !todo.completed} : todo
);
default:
return state;
}
};
export default todos;
#Todoをクリックしてcompleted属性を変更する
まずは、mapDispatchToProps
を作成してdispatchを
propsとして使えるようにしましょう。toggleTodoという名前でdispatchをstoreに格納します。
import {connect} from 'react-redux';
import TodoList from '../components/TodoList';
import {toggleTodo} from '../actions';
const mapStateToPorops = state => {
return {todos: state.todos};
};
const mapDispatchToProps = dispatch => {
return {
toggleTodo: id => {
dispatch(toggleTodo(id));
},
};
};
const VisibleTodoList = connect(
mapStateToPorops,
mapDispatchToProps
)(TodoList);
export default VisibleTodoList;
これでTodoListでtoggleTodoが使えるようになったので、TodoコンポーネントのonClick属性にtodoのidを引数としてtoggleTodoを渡します。
import React from 'react';
import PropTypes from 'prop-types';
import Todo from './Todo';
const TodoList = ({todos, toggleTodo}) => {
return (
<ul>
{todos.map(todo => (
<Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} />
))}
</ul>
);
TodoList.propTypes = {
todos: PropTypes.arrayOF(
PropTypes.shape({
id: PropTypes.number.isRequired,
text: PropTypes.string.isRequired,
}).isRequired
).isRequired,
};
};
export default TodoList;
Todoコンポーネント内でpropsとして渡されたtoggleTodoをonClick属性に付与します。
import React from 'react';
import PropTypes from 'prop-types';
const Todo = ({onClick, completed, text}) => {
return (
<li
onClick={onClick}
style={{textDecoration: completed ? 'line-through' : 'none'}}>
{text}
</li>
);
};
Todo.propTypes = {
completed: PropTypes.bool.isRequired,
text: PropTypes.string.isRequired,
};
export default Todo;
以上でTodoをクリックした際に取り消し線を引く機能を実装できました!
次回は表示するTodoを完了・未完了によって分ける「Filter Todo」機能を実装したいと思います。
#リファレンス