Help us understand the problem. What is going on with this article?

immerで複雑な構造のオブジェクトを扱う

More than 1 year has passed since last update.

複雑な構造のオブジェクトに何か値を追加する際、現在の構造を壊さずに値を追加しなければならないのでスプレッド演算子をたくさん使ったコードになりがちです。

イメージとしてはこんな感じのやつです。

const user; // 変更前のユーザー。複雑な構造をしている
const additionalHoge = ['hoge', 'huga']; // 追加したいデータ

const newUser = {
  ...user,
  detail: {
    ...user.detail,
    hoge: [...user.detail.hoge, ...additionalHoge],
  }
}

こういう雰囲気のコードをいい感じにリファクタできるimmerというライブラリを最近知りました。mobxの作者の方が作ったライブラリみたいです。

immerを使うと上のやつはこんな感じで書き直せます。
元の変数 user には変更はなく、新たに変更が反映されたオブジェクト newUser が返ってきます。
元の構造を維持するための ...user みたいなコードは一掃出来るのでどこに変化があるのかがわかりやすいです。

import produce from 'immer';

const user; // 変更前のユーザー
const additionalHoge = ['hoge', 'huga']; // 追加したいデータ

const newUser = produce(user, draftUser => {
  draftUser.detail.hoge = [...draftUser.detail.hoge, ...additionalHoge];
});

これくらいの構造のネストであれば、そのままjsで書いてもいいと思いますが、ネストが何重にもなればなるほど、immerの見やすさが顕著に出てくると思います。

使いどころとしてはreduxのreducerで使うような例が公式のreadmeにものってます。
他に使えそうと思ったところとして、react-apolloでreact-infinite-scrollerを用いた無限スクロールを行う際、元のデータにデータを追加するコードがスプレッド演算子だらけになるので、ここでも使えるなあと思いました。

react-apollのこういう感じのコードを綺麗に出来る。参考

          return {
            ...previousResult,
            search: {
              ...previousSearch,
              nodes: [...previousNodes, ...currentNodes],
              pageInfo: currentSearch.pageInfo,
            },
          };
pokotyan
admin-guild
「Webサービスの運営に必要なあらゆる知見」を共有できる場として作られた、運営者のためのコミュニティです。
https://admin-guild.slack.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away