LoginSignup
1
3

More than 3 years have passed since last update.

Redux stateにimmutable.jsを使う

Posted at

immutable.jsをRedux stateに使ってみました。本記事は簡単な使い方の紹介になります。
Immutable collections for JavaScript

Immutabilityはアプリのパフォーマンスに貢献します。加えてプログラミングやデバッグをよりシンプルにしてくれます。

ImmutabilityとReduxの関連は、以下の記事に詳しく書いてあります。
Redux FAQ: Immutable Data

Todoアプリ

React ReduxにあるTodoアプリにimmutable.jsを導入してみました。

環境は簡単に構築できます。

yarn create react-app todo-immutable
cd todo-immutable
yarn add redux react-redux classnames
yarn add immutable
rm -rf src

4個のファイルを修正しました。必要に応じて、オリジナルと比べてみてください。ざっくり言って、コードが短くなっています。

state.todosをMapのListとして利用していきます。

src/redux/reducers/todos.js
import { ADD_TODO, TOGGLE_TODO } from "../actionTypes";
// ListとMapを使います
import { List, Map } from "immutable";

export default function(state = List(), action) {
  switch (action.type) {
    case ADD_TODO: {
      const { id, content } = action.payload;
      return state.push( // ListにMapを追加
        Map({
          id,
          content,
          completed: false
        })
      );
    }

    case TOGGLE_TODO: {
      const { id } = action.payload;
      return state.map(todo => { // Listのmapで処理
        if (todo.get("id") === id) {
          return todo.update("completed", v => !v); // Mapのupdate
        }
        return todo;
      });
    }

    default:
      return state;
  }
}

ListのfilterやfilterNotを使ってセレクタ関数を定義します。Mapのtodoにはtodo.get()でアクセスします。

src/redux/selectors.js
import { VISIBILITY_FILTERS } from "../constants";

export const getTodosByVisibilityFilter = (store, visibilityFilter) => {
  switch (visibilityFilter) {
    case VISIBILITY_FILTERS.COMPLETED:
      // Listのfilter関数。Mapのget関数。
      return store.todos.filter(todo => todo.get("completed"));
    case VISIBILITY_FILTERS.INCOMPLETE:
      // ListのfilterNot関数。Mapのget関数。
      return store.todos.filterNot(todo => todo.get("completed"));
    case VISIBILITY_FILTERS.ALL:
    default:
      return store.todos;
  }
};

toObject()でMapをJSON Objectに変換します。

src/components/Todo.js
import React from "react";
import { connect } from "react-redux";
import cx from "classnames";
import { toggleTodo } from "../redux/actions";

const Todo = ({ todo, toggleTodo }) => {
 // toObject()でMapをJSON Objectに変換。
 const { id, content, completed } = this.props.todo.toObject();
 return (
  <li className="todo-item" onClick={() => toggleTodo(id)}>
    {todo && completed ? "" : ""}{" "}
    <span
      className={cx(
        "todo-item__text",
        todo && completed && "todo-item__text--completed"
      )}
    >
      {content}
    </span>
  </li>
  );
}

// export default Todo;
export default connect(
  null,
  { toggleTodo } // mapDispatchToProps を Object として定義
)(Todo);

Mapのget関数でidを取得します。

src/components/TodoList.js
import React from "react";
import { connect } from "react-redux";
import Todo from "./Todo";
import { getTodosByVisibilityFilter } from "../redux/selectors";
import { VISIBILITY_FILTERS } from "../constants";

const TodoList = ({ todos }) => (
  <ul className="todo-list">
    {todos && todos.size
      ? todos.map((todo, index) => {
          // Mapのget関数でidを取得
          return <Todo key={`todo-${todo.get("id")}`} todo={todo} />;
        })
      : "No todos, yay!"}
  </ul>
);


const mapStateToProps = state => {
  const { visibilityFilter } = state;
  const todos = getTodosByVisibilityFilter(state, visibilityFilter);
  return { todos };
};
// export default TodoList;
export default connect(mapStateToProps)(TodoList);

今回は以上です。

1
3
0

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
1
3