Ответ 1
Да, использование идентификаторов в нескольких магазинах, похожих на реляционную базу данных, - это способ сделать это правильно.
В вашем примере предположим, что вы хотите оптимистично поместить новую карту в конкретный столбец и что карта может находиться только в одном столбце (один столбец для многих карт).
Карты в CardStore могут выглядеть так:
_cards: {
'CARD_1': {
id: 'CARD_1',
columnID: 'COLUMN_3',
title: 'Go to sleep',
text: 'Be healthy and go to sleep on time.',
},
'CARD_2': {
id: 'CARD_2',
columnID: 'COLUMN_3',
title: 'Eat green vegetables',
text: 'They taste better with onions.',
},
}
Обратите внимание, что я могу ссылаться на карту по id, и я также могу получить идентификатор внутри объекта. Это позволяет мне иметь такие методы, как getCard(id)
, а также иметь возможность извлекать идентификатор определенной карты в пределах слоя представления. Таким образом, у меня может быть метод deleteCard(id)
, который вызывается в ответ на действие, потому что я знаю идентификатор в представлении.
Внутри хранилища карт у вас будет getCardsByColumn(columnID)
, что будет простой картой над объектами карты, и это приведет к созданию массива карт, которые вы могли бы использовать для визуализации содержимого столбца.
Относительно механики оптимистичных обновлений и того, как это влияет на использование идентификаторов:
Вы можете использовать идентификатор на стороне клиента, который устанавливается в пределах одного и того же закрытия, который будет обрабатывать ответ XHR, и очистить идентификатор клиентской стороны, когда ответ вернется как успешный, или вместо этого откатиться от ошибки. Закрытие позволяет удерживать идентификатор клиентской стороны до тех пор, пока ответ не вернется.
Многие люди создадут модуль WebAPIUtils, который будет содержать все методы, связанные с закрытием, сохраняя идентификатор на стороне клиента и запрос/ответ. Создатель действия (или хранилище) может вызвать этот модуль WebAPIUtils для инициирования запроса.
Итак, у вас есть три действия:
- инициировать запрос
- Успех дескриптора
- Ответ на дескриптор
В ответ на действие, инициирующее запрос, ваш магазин получает идентификатор клиентской стороны и создает запись.
В ответ на успех/ошибку ваш магазин снова получает идентификатор на стороне клиента и либо изменяет запись как подтвержденную запись с реальным идентификатором, либо вместо этого откатывает запись. Вы также хотели бы создать хороший UX вокруг этой ошибки, например, повторить попытку пользователя.
Пример кода:
// Within MyAppActions
cardAdded: function(columnID, title, text) {
var clientID = this.createUUID();
MyDispatcher.dispatch({
type: MyAppActions.types.CARD_ADDED,
id: clientID,
columnID: columnID,
title: title,
text: text,
});
WebAPIUtils.getRequestFunction(clientID, "http://example.com", {
columnID: columnID,
title: title,
text: text,
})();
},
// Within WebAPIUtils
getRequestFunction: function(clientID, uri, data) {
var xhrOptions = {
uri: uri,
data: data,
success: function(response) {
MyAppActions.requestSucceeded(clientID, response);
},
error: function(error) {
MyAppActions.requestErrored(clientID, error);
},
};
return function() {
post(xhrOptions);
};
},
// Within CardStore
switch (action.type) {
case MyAppActions.types.CARD_ADDED:
this._cards[action.id] = {
id: action.id,
title: action.title,
text: action.text,
columnID: action.columnID,
});
this._emitChange();
break;
case MyAppActions.types.REQUEST_SUCCEEDED:
var tempCard = this._cards[action.clientID];
this._cards[action.id] = {
id: action.id,
columnID: tempCard.columnID,
title: tempCard.title,
text: tempCard.text,
});
delete this._cards[action.clientID];
break;
case MyAppActions.types.REQUEST_ERRORED:
// ...
}
Пожалуйста, не слишком увлекайтесь деталями имен и спецификой этой реализации (возможно, существуют опечатки или другие ошибки). Это просто пример кода для объяснения шаблона.