Илья Малявин, Яндекс
Илья Малявин, Разработчик интерфейсов
У нас есть топоры разных моделей, цен и несколько партнеров-поставщиков
Как бы мы это сделали в середине прошлого десятилетия?
или то, что мы отдаем шаблонизатору для первоначального рендеринга
[{
title: 'Axe 2000',
offers: [{
price: 500,
shop: {
title: 'Тверские топоры'
}
}, {
price: 200,
shop: {
title: 'Новгородские топоры'
}
}]
}];
Но тут есть проблемы:
О чем следовало подумать в первую очередь?
[{
title: 'Axe 2000',
entity: 'model',
offers: [{
entity: 'offer',
price: 500,
shop: {
entity: 'shop',
id: "tverShop",
title: 'Тверские топоры'
}
}, {
entity: 'offer',
price: 200,
shop: {
entity: 'shop',
id: "novgShop",
title: 'Новгородские топоры'
}
}]
}];
View data
Entities
[{
title: 'Axe 2000',
entity: 'model',
offers: [{
entity: 'offer',
price: 500,
shop: {
entity: 'shop',
id: "tverShop",
title: 'Тверские топоры'
}
}, {
entity: 'offer',
price: 200,
shop: {
entity: 'shop',
id: "tverShop",
title: 'Тверские топоры'
}
}]
}];
Что это значит?
Redux подталкивает нас к нормализации:
Подробнее можно почитать в документации: https://redux.js.org/recipes/structuringreducers/normalizingstateshape
Небольшая библиотека для конвертации вложенных данных в нормализованные на основе описанной схемы
https://github.com/paularmstrong/normalizr
{
items: [{
entity: 'offer',
id: 1
}],
entities: {
offer: {
"1": {
entity: 'offer',
price: 500,
shop: "tverShop",
},
},
shop: {
"tverShop": {
entity: 'shop',
title: "Тверские топоры"
},
},
},
}
Другими словами, набор топоров становится виджетом
Это независимая часть приложения, которая:
как же дедупликация данных?
как обеспечить независимость виджетов в store?
{
collections: {
offer: {
1: {id: "1", price: 500, shop: "tverShop"},
2: {id: "2", price: 233, shop: "tverShop"},
3: {id: "3", price: 600, shop: "tverShop"},
4: {id: "4", price: 350, shop: "tverShop"},
},
shops: {"tverShop": {title: 'Новгородские топоры'}}
}
}
{
widgets: {
"axesPack1": {
offerIds: [1, 2, 3],
},
"axesPack2": {
offerIds: [2, 3, 4],
},
},
}
{
collections: {
offer: {
1: {id: "1", price: 500, shop: "tverShop"},
2: {id: "2", price: 233, shop: "tverShop"},
3: {id: "3", price: 600, shop: "tverShop"},
4: {id: "4", price: 350, shop: "tverShop"},
},
shops: {"tverShop": {title: 'Новгородские топоры'}}
}
widgets: {
"axesPack1": {
offerIds: [1, 2, 3],
title: 'Топоры по лучшим ценам',
},
"axesPack2": {
offerIds: [2, 3, 4],
title: 'Топоры специально для вас',
},
},
}
Чтобы гарантировать принцип независимости, используем свою обертку над connect
function mapStateToProps(widgetData, collections) {
// Берем id нужных нам топоров
const {offerIds} = widgetData;
return {
// Для каждого id получаем сущность из коллекции
axes: offerIds.map(id => collections.offer[id]),
};
}
Детальный рассказ про нашу виджетную систему от Паши Павелко: