LoginSignup
3

More than 3 years have passed since last update.

React + ReduxでTodoアプリを作ってみよう!『Toggle Todo編』

Last updated at Posted at 2019-05-03

概要

前回の記事ではTodoアプリにTodoを追加する『Add Todo』機能を実装しました。今回は、追加されたTodoをクリックした際に斜線を引けるようにし、Todoの未・済を判別出来る機能を実装したいと思います!

前回の記事
React + ReduxでTodoアプリを作ってみよう!『Add Todo編』

completed属性を付与する

completed属性を付与することで、Todoが完了済みなのか未完了なのかを判別できるようにしましょう!Todoを追加する際にcompleted属性にfalseをデフォルトとして設定します!

src/reducers/todos.js
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を反映させましょう!

src/components/Todo.js
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を取得します。

src/actions/index.js
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.typeTOGGLE_TODOの際の状態遷移の方法を記述しましょう。この中では、stateに保管されているTodoのidと横線を引きたいTodoのidを比較し、お互いに一致するようであれば、一致したidのTodoが持っているcompleted属性を逆転させます。

src/reducers/todo.js
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に格納します。

src/containers/VisibleTodoList.js
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を渡します。

src/components/TodoList.js
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属性に付与します。

src/components/Todo.js
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をクリックした際に取り消し線を引く機能を実装できました!

ezgif.com-optimize (2).gif

次回は表示するTodoを完了・未完了によって分ける「Filter Todo」機能を実装したいと思います。

リファレンス

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3