Redux - Normalization
非正規データの弊害
- ネストされたデータをそのまま扱うことには下記の弊害がある
- 同一データが複数の場所に散在するため、一貫性のある更新が困難
- ネストしたデータを更新する reducer は見づらい
- ネストしたデータを更新すると祖先のデータも更新され、結果として大量の再描写が発生する
- このことから、正規化してデータを持つことが推奨される
// 非正規データの例
const blogPosts = [
{
id: 'post1',
author: { username: 'user1', name: 'User 1' },
body: '......',
comments: [
{
id: 'comment1',
author: { username: 'user2', name: 'User 2' },
comment: '.....',
},
{
id: 'comment2',
author: { username: 'user3', name: 'User 3' },
comment: '.....',
},
],
},
{
id: 'post2',
author: { username: 'user2', name: 'User 2' },
body: '......',
comments: [
{
id: 'comment3',
author: { username: 'user3', name: 'User 3' },
comment: '.....',
},
{
id: 'comment4',
author: { username: 'user1', name: 'User 1' },
comment: '.....',
},
{
id: 'comment5',
author: { username: 'user3', name: 'User 3' },
comment: '.....',
},
],
},
];
正規化の基本コンセプト
- データの種類ごとに「テーブル」を state に作成する
- テーブルは以下の 2 つのオブジェクトを持つ
- 「キーが ID、値がデータ」のオブジェクト(下記の
byId
)- ここで実際のデータを管理する
- 個々のアイテムを参照するときは ID を使って行う
- 全ての ID を持つ配列(下記の
allIds
)
- 「キーが ID、値がデータ」のオブジェクト(下記の
- 必要に応じてNormalizrなどのライブラリを使うと良い
// 正規化済みのデータ
const normalizedState = {
posts: {
byId: {
post1: {
id: 'post1',
author: 'user1',
body: '......',
comments: ['comment1', 'comment2'],
},
post2: {
id: 'post2',
author: 'user2',
body: '......',
comments: ['comment3', 'comment4', 'comment5'],
},
},
allIds: ['post1', 'post2'],
},
comments: {
byId: {
comment1: {
id: 'comment1',
author: 'user2',
comment: '.....',
},
comment2: {
id: 'comment2',
author: 'user3',
comment: '.....',
},
comment3: {
id: 'comment3',
author: 'user3',
comment: '.....',
},
comment4: {
id: 'comment4',
author: 'user1',
comment: '.....',
},
comment5: {
id: 'comment5',
author: 'user3',
comment: '.....',
},
},
allIds: ['comment1', 'comment2', 'comment3', 'commment4', 'comment5'],
},
users: {
byId: {
user1: {
username: 'user1',
name: 'User 1',
},
user2: {
username: 'user2',
name: 'User 2',
},
user3: {
username: 'user3',
name: 'User 3',
},
},
allIds: ['user1', 'user2', 'user3'],
},
};