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.

【Vue】deepmergeの使い方。ネストしたオブジェクトをマージする。

Posted at

jsのライブラリdeepmergeの使い方。ネストしたオブジェクトをマージする方法と注意点について

##目次

  1. deepmergeとは?
  2. 上書きされる場合
  3. 上書きにならない場合
    1. プロパティ名が異なる
    2. プロパティの値がどちらも配列
    3. 配列内でプロパティ名が重複
  4. 配列の結合(オブジェクトでない場合)
  5. 公式ページの結合事例を解読してみる
  6. Vueの確認用ソースコード

##deepmergeとは? オブジェクトを結合できるnpmのライブラリ。 インポートして使用する。
インポート方法

import merge from 'deepmerge'

インポート名はなんでもいい。ここではmergeを使用。

npm公式 deepmerge


**▼deepmergeの注意点**

結合したときに、元のデータの形によって上書きされることもある。パターン別に内容を確認していく。

##deepmergeのパターン

  1. 上書きされる場合
    1. プロパティ名が同じ、かつ、どちらか一方の値が配列でない
  2. 上書きにならない場合
    1. プロパティ名が異なる
    2. プロパティの値がどちらも配列
    3. 配列内でプロパティ名が重複

##1. 上書きされる場合
まずは上書きされるパターンから。

同じプロパティ名で値が配列でない場合、マージ結果は上書きされたものになる。

上書きの例1
let obj1 = { id: 10 },
let obj2 = { id: 20 },

console.log(merge(obj1, obj2))

//出力
{ "id": 20 }

出力は{ "id": 20 }となる。第1引数の値は上書きされて消える。


###▼上書きの例3 プロパティの値が入れ子になっていても、配列でなければこちらも上書きされる。
上書きの例2
let obj1 = { id: {b:10} },
let obj2 = { id: {b:20} },

console.log(merge(obj1, obj2))

//出力
{ "id": { "b": 20 } }

###▼上書きの例3 片方のみが配列の場合も上書きされる。
上書きの例3
let obj1 = { id: [10] },
let obj2 = { id: 20 },

console.log(merge(obj1, obj2))

//出力
{ "id": 20 }
上書きの例3'
let obj1 = { id: 10 },
let obj2 = { id: [20] },

console.log(merge(obj1, obj2))

//出力
{ "id": [20] }

プロパティ名が同じ、かつ、どちらか一方の値が配列でない場合は、後ろの引数の値でマージされるので注意が必要。


##2. 上書きにならない場合

###2-1. プロパティ名が異なる
プロパティ名が異なる場合は上書きにならず、意図した通りにマージしてくれる。

上書きなし例1
let obj1 = { x: 10 },
let obj2 = { y: 20 },

console.log(merge(obj1, obj2))

//出力
{ "x": 10, "y": 20 }

###2-2. プロパティの値がどちらも配列 プロパティの値がどちらも配列の場合は結合できる。
上書きなし例1
let obj1 = { a: [10] },
let obj2 = { a: [20] },

console.log(merge(obj1, obj2))

//出力
{ "a": [ 10, 20 ] }

###複数の場合
複数のプロパティが入り混じっている場合は、どちらも配列の場合とプロパティ名が異なる場合は結合。それ以外は上書きとなる。

let obj1 = { a: [10],  b:30, c:50},
let obj2 = { a: [20],  b:400, d:600},

console.log(merge(obj1, obj2))

//出力
{ "a": [ 10, 20 ], "b": 400, "c": 50, "d": 600 }

aは配列どおしなので結合。
bは配列でないので上書き。
c, dはプロパティ名が重複していないので結合となる。


##2-3. 配列内でプロパティ名が重複
プロパティ名が被っていても、配列の中であれば上書きなしでそれぞれ結合される。

let obj1 = { a: [{ x: 1 }] },
let obj2 = { a: [{ x: 2 }] },

console.log(merge(obj1, obj2))

//出力
{ "a": [ { "x": 1 }, { "x": 2 } ] }

プロパティaの中の配列で、プロパティxが重複しているが、それぞれ個別に結合される。

###複数の場合

let obj1 = { b:[{x:2, y:3}] },
let obj2 = { b:[{x:4, y:5}] },

console.log(merge(obj1, obj2))

//出力
{ "b": [ { "x": 2, "y": 3 }, { "x": 4, "y": 5 } ] }

##配列の結合(オブジェクトでない場合)

オブジェクトではなく配列をマージすると、ただの結合になる。

配列
let arr1 = [1,2,[3]],
let arr2 = [9,8,[7]],

console.log(merge(arr1, arr2))

//出力
[ 1, 2, [ 3 ], 9, 8, [ 7 ] ]

##公式ページの結合事例を解読してみる

最後に公式ページの結合事例を見てみる。

結合する要素xとy
const x = {
        foo: { bar: 3 },
        array: [{
          does: 'work',
          too: [ 1, 2, 3 ]
        }]
      },
const y = {
        foo: { baz: 4 },
        quux: 5,
        array: [{
            does: 'work',
            too: [ 4, 5, 6 ]
        }, {
            really: 'yes'
        }]
      }

・プロパティfooの中身はbarとbazでプロパティ名が異なるためどちらも残る。

・arrayの中も配列なのでどちらも残る。配列の中のプロパティ名が同じでも個別に出力される。

・quuxはプロパティ名が固有(異なる)ためそのまま出力される。

結合結果
const output = {
    foo: {
        bar: 3,
        baz: 4
    },
    array: [{
        does: 'work',
        too: [ 1, 2, 3 ]
    }, {
        does: 'work',
        too: [ 4, 5, 6 ]
    }, {
        really: 'yes'
    }],
    quux: 5
}

##Vueの確認用ソースコード

▼ブラウザの表示
image.png

.vueソースコード
<template>
  <div>
    <p>{{obj}}</p>
    <v-btn @click="deepMerge(obj1, obj2)"> 
      (obj1, obj2)
    </v-btn>
    <v-btn @click="deepMerge(obj3, obj4)"> 
      (obj3, obj4)
    </v-btn>
    <v-btn @click="deepMerge(obj5, obj6)"> 
      (obj5, obj6)
    </v-btn>
    <v-btn @click="deepMerge(obj7, obj8)"> 
      (obj7, obj8)
    </v-btn>
    <v-btn @click="deepMerge(arr1, arr2)"> 
      (arr1, arr2)
    </v-btn>
    <v-btn @click="deepMerge(val1, val2)"> 
      (val1, val2)
    </v-btn>
    <v-btn @click="deepMerge(x, y)"> 
      (x, y)
    </v-btn>
  </div>
</template>

<script>
import merge from 'deepmerge'

export default {
  data(){
    return{
      obj: {},

      obj1: { b:[{x:2, y:3}] },
      obj2: { b:[{x:4, y:5}] },
      obj3: { id: {b:10} },
      obj4: { id: {b:20} },
      obj5: { x: 10 },
      obj6: { y: 20 },
      obj7: { a: [10],  b:30, c:50},
      obj8: { a: [20],  b:400, d:600},
      arr1: [1,2,[3]],
      arr2: [9,8,[7]],
      val1: {width: '50%'},
      val2: {width: '33%'},
      x:{
        foo: { bar: 3 },
        array: [{
          does: 'work',
          too: [ 1, 2, 3 ]
        }]
      },
      y:{
        foo: { baz: 4 },
        quux: 5,
        array: [{
            does: 'work',
            too: [ 4, 5, 6 ]
        }, {
            really: 'yes'
        }]
      }

    }
  },
  methods:{
    deepMerge(a, b){
      this.obj =  merge(a,b)
    }
  }
}
</script>

一つづつパターンを分けていくと、どういったパターンで上書きされるかがわかる。
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?