1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vuexでネストしたデータに悩まされている方に知って欲しいnormalizr

Last updated at Posted at 2020-08-09

はじめに

Vuexを使用している時に、ネストしたデータを非常に扱いにくいと感じたことはないでしょうか?
今回はそういった悩みを持って開発をしている人向けにnomalizrを紹介していきたいと思います。

normalizrとは

https://github.com/paularmstrong/normalizr
↑が公式のライブラリで
下記のように記載してあります。

Motivation
Many APIs, public or not, return JSON data that has deeply nested objects. Using data in this kind of structure is often very difficult for JavaScript applications, especially those using Flux or Redux.

Solution
Normalizr is a small, but powerful utility for taking JSON with a schema definition and returning nested entities with their IDs, gathered in dictionaries.

簡単に要約すると

多くのAPIはオブジェクトが深くネストされているJSONデータを返してくる
このようなデータはFluxやReduxで非常に扱いにくい
Normalizrはスキーマ定義でJSONを取得し、ネストされたエンティティとID一覧を返す強力なものです。

具体的にはどう使う?

よくあるユーザーの投稿と投稿に対するコメントいうテーブルを考えてみましょう。

簡易テーブル構造

User
    id - integer
    name - string

posts
    id - integer
    title - string
    user_id - integer

comments
    id - integer
    comment - string
    user_id - integer
    post_id - integer

投稿一覧をAPIから取得した場合は下記のようなデータが帰ってきます。

[
  {
    id: 1,
    title: 'Post1',
    user: {
      id: 1,
      name: 'Tanaka'
    },
    comments:[{
      id: 1,
      comment: 'comment1',
      user: {
        id:2,
        name: 'yamada'
      }
    }]
  },
  {
    id: 2,
    title: 'Post2',
    user: {
      id: 1,
      name: 'Tanaka'
    },
    comments:[{
      id: 2,
      comment: 'comment2',
      user: {
        id:2,
        name: 'yamada'
      }
    }]
  }
]

このままだと例えばですが、コメントしたユーザーの名前をフロント側で編集ができる場合、データが正規化されてないので
全ての同じユーザーの名前を変更する必要があり、非常に辛い作業となってしまいます。

使い方

公式ドキュメントを見ればある程度使い方は書いてありますが、実際に使ってみます。

まずはインストール

npm install normalizr

storeでnomalizrを使用する

postsのstore
import { normalize, schema } from 'normalizr'

// user用のエンティティを定義
// entities.usersにuserデータが格納される。
const user = new schema.Entity('users')
// comment用のエンティティを定義
// entities.commentsにcommentデータが格納される。
const comment = new schema.Entity('comments', {
  // commentはuserデータを持っているので下記のように定義
  user,
})
// post用のエンティティを定義
// entities.postsにcommentデータが格納される。
const post = new schema.Entity('posts', {
  // postはuserデータを持っているので下記のように定義
  user,
  // postはcommentを配列で持っているので下記のように定義
  comments: [comment],
})
// APIがpostエンティティの配列を返すようなデータ構造なのでschema.Arrayにpostを入れる
// [post]と書いても良い
const postsSchema = new schema.Array(post)

exports const mutations = {
  // ActionでpostDataをAPIから取得し、setPostsに渡しているイメージ
  setPosts(state, postData) {
    // normalizeを使用して、正規化データを取得
    const posts = normalize(postData, postsSchema)
    state.entities = posts.entities
    state.result = posts.result
  },
}
// 下記のようなgetterを用意して使うようなイメージ
export const getters = {
  postGetter: (state) => state.entities.posts ?? {},
  commentGetter: (state) => state.entities.comments ?? {},
  userGetter: (state) => state.entities.users ?? {},
}

export const state = () => ({
  entities: {
  },
  result: []
})

上記のようにデータをいれてあげることで、
state.entities.postsには

{
  '1': {
    id: 1,
    title: 'Post1',
    user: 1,
    comments: [
      1
    ]
  },
  '2': {
    id: 2,
    title: 'Post2',
    user: 1,
    comments: [
      2
    ]
  }
}

state.entities.usersには

{
  '1': {
    id: 1,
    name: 'Tanaka'
  },
  '2': {
    id: 2,
    name: 'yamada'
  }
}

state.entities.commentsには

{
  '1': {
    id: 1,
    comment: 'comment1',
    post_id: 1,
    user: 2
  },
  '2': {
    id: 2,
    comment: 'comment2',
    post_id: 2,
    user: 2
  }
}

というような正規化されたデータが入り、扱いやすくなります。

最後に

今までVuexでネストされたデータの扱いに困っていた方は是非normalizrを使用してみてください。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?