リファクタリング : actionsの分割 (STEP 1 : 誰でも読み込み・書き込みできるタスク管理アプリを作る - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

actionsの変更

actions/index.jsのサイズが大きくなってきたので、分割します。また、下記の点もリファクタリングします。

  • action typeを定数で定義する
  • 個々のactionを定義する

index.jsにaction typeをまとめます。

src/actions/index.js

// todo actions
export const ADD_TODO_REQUEST = 'ADD_TODO_REQUEST';
export const ADD_TODO_SUCCESS = 'ADD_TODO_SUCCESS';
export const ADD_TODO_ERROR   = 'ADD_TODO_ERROR';
export const TOGGLE_TODO_REQUEST = 'TOGGLE_TODO_REQUEST';
export const TOGGLE_TODO_SUCCESS = 'TOGGLE_TODO_SUCCESS';
export const TOGGLE_TODO_ERROR   = 'TOGGLE_TODO_ERROR';

// visibility filter actions
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';

todoActions.jsファイルを新規作成し、index.jsからtodo関連のactionをコピーしたあと、リファクタリングします。

src/actions/todoActions.js

import {ADD_TODO_REQUEST, ADD_TODO_SUCCESS, ADD_TODO_ERROR,
  TOGGLE_TODO_REQUEST, TOGGLE_TODO_SUCCESS, TOGGLE_TODO_ERROR}
   from './'

const addTodoRequest = () => ({
  type: ADD_TODO_REQUEST
})

const addTodoSuccess = () => ({
  type: ADD_TODO_SUCCESS
})

const addTodoError = err => ({
   type: ADD_TODO_ERROR,
   err
})

const toggleTodoRequest = (text, completed) => ({
  type: TOGGLE_TODO_REQUEST,
  text,
  completed
})

const toggleTodoSuccess = (text, completed) => ({
  type: TOGGLE_TODO_SUCCESS,
  text,
  completed
})

const toggleTodoError = (text, completed, err) => ({
  type: TOGGLE_TODO_ERROR,
  text,
  completed,
  err
})

export const addTodo = text => {
  return (dispatch, getState, {getFirebase}) => {
    dispatch(addTodoRequest());
    const firebase = getFirebase();
    firebase.push('todos', {completed: false, text})
    .then(() => {
      dispatch(addTodoSuccess());
    }).catch(err => {
      dispatch(addTodoError(err));
    });
  }
}

export const toggleTodo = id => {
  return (dispatch, getState, {getFirebase}) => {
    const firebase = getFirebase();
    const state = getState();
    const todo = state.firebase.data.todos[id];
    dispatch(toggleTodoRequest(todo.text, !todo.completed));
    firebase.update(`todos/${id}`, {completed: ! todo.completed})
    .then(() => {
      dispatch(toggleTodoSuccess(todo.text, !todo.completed));
    }).catch(err => {
      dispatch(toggleTodoError(todo.text, !todo.completed, err));
    });
  }
}

だいぶ長くなりましたが、プロダクトが大きくなるならばこの方が見通しが良くなります。

次に、visibilityFilterActions.jsファイルを新規作成し、index.jsからvisibilityFilter関連のactionをコピーしたあと、リファクタリングします。

src/actions/visibilityFilterActions.js

import { SET_VISIBILITY_FILTER } from './'

export const setVisibilityFilter = filter => ({
  type: SET_VISIBILITY_FILTER,
  filter
})

export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
}

reducersの変更

reducerの変更をします。action typeを文字列から定数に変更します。

src/reducers/todos.js

import {ADD_TODO_REQUEST, ADD_TODO_SUCCESS, ADD_TODO_ERROR,
  TOGGLE_TODO_REQUEST, TOGGLE_TODO_SUCCESS, TOGGLE_TODO_ERROR}
   from '../actions/'

const getStringForCompleted = (completed) => (
  completed ? '完了' : '未完了'
)

const todos = (state = {}, action) => {
  switch (action.type) {
    case ADD_TODO_REQUEST:
      return {...state, notice: 'データを送信中'}
    case ADD_TODO_SUCCESS:
      return {...state, notice: '送信完了しました'}
    case ADD_TODO_ERROR :
      return {...state, notice: 'エラーが発生しました'}
    case TOGGLE_TODO_REQUEST:
      return {...state, notice:
        '"' + action.text + '"のステータスを"'
        + getStringForCompleted(action.completed)
        + '"に変更中'}
    case TOGGLE_TODO_SUCCESS:
      return {...state, notice:
        '"' + action.text + '"のステータスを"'
        + getStringForCompleted(action.completed)
        + '"に変更しました'}
    case TOGGLE_TODO_ERROR :
      return {...state, notice:
        '"' + action.text + '"の更新中にエラーが発生しました。'}
    default:
      return state
  }
}

export default todos;

src/reducers/visibilityFilter.js

import { SET_VISIBILITY_FILTER } from '../actions/'
import { VisibilityFilters } from '../actions/visibilityFilterActions'

const visibilityFilter = (state = VisibilityFilters.SHOW_ALL, action) => {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

export default visibilityFilter;

import文の修正

Importを修正していきます。

src/components/Footer.js

import { VisibilityFilters } from '../actions/visibilityFilterActions'  // 変更

src/containers/AddTodo.js

import { addTodo } from '../actions/todoActions'  // 変更

src/containers/FilterLink.js

import { setVisibilityFilter } from '../actions/visibilityFilterActions'  // 変更

src/containers/VisibleTodoList.js

import { toggleTodo } from '../actions/todoActions'  // 変更

以上でactionsの分割とリファクタリングは終了です。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com