Подход к разрешению зависимостей и оптимистичным обновлениям в реагирующих приложениях
В архитектуре, где объекты имеют много сложных отношений, каковы некоторые поддерживаемые подходы к решению
- Разрешение зависимостей
- Оптимистичные Обновления
в реакции приложений?
Например, учитывая этот тип схемы:
```
type Foo {
...
otherFooID: String,
bars: List<Bar>
}
type Bar {
...
bizID: String,
}
type Biz {
...
}
```
Пользователь может захотеть сохранить следующее ->
firstBiz = Biz();
secondBiz = Biz();
firstFoo = Foo({bars: [Bar({biz: firstBiz})]
secondFoo = Foo({bars: [Bar({biz: secondBiz})] otherFooId: firstFooId.id})
Первая проблема: выбор реальных идентификаторов
Первая проблема с вышеупомянутым имеет правильную id
, т.е. чтобы сохранить secondFoo, ему нужно знать фактический идентификатор firstFoo.
Чтобы решить эту проблему, мы могли бы найти компромисс: позволить клиенту выбрать идентификатор, используя что-то вроде uuid. Я не вижу в этом ничего страшного, поэтому мы можем сказать, что это может сработать.
Вторая проблема: сохранение в порядке
Даже если мы определяем идентификаторы из внешнего интерфейса, сервер все равно должен получать эти запросы на сохранение по порядку.
```
- save firstFoo
// okay. now firstFoo.id is valid
- save secondFoo
// okay, it was able to resolve otherFooID to firstFoo
```
Причиной здесь является то, что сервер должен гарантировать, что любой идентификатор, на который ссылаются, является действительным.
```
- save secondFoo
// backend throws an error otherFooId is invalid
- save firstfoo
// okay
```
Я не уверен, что лучший способ решить эту проблему
Текущие подходы, которые приходят на ум
Есть пользовательские действия, которые выполняют координацию через обещания
save(biz).then(_ => save(Bar).then(_ => save(firstFoo)).then(_ => save(second)
Недостатком здесь является то, что это довольно сложно, и число таких комбинаций будет продолжать расти
Создайте помощника в ожидании / разрешении
const pending = {} const resolve = (obj, refFn) => { return Promise.all(obj, refFn(obj)); } const fooRefs = (foo) => { return foo.bars.map(bar => bar.id).concat(foo.otherFooId); } pending[firstFoo].id = resolve(firstFoo, fooRefs).then(_ => save(firstFoo))
```
Проблема с 2. заключается в том, что он может легко вызвать кучу ошибок, если мы забудем разрешить или добавить в ожидание.
Потенциальные решения
Кажется, что Relay или Om затем могут решить эти проблемы, но я хотел бы что-то менее мощное. Возможно, что-то, что может работать с редуксом, или, может быть, мне не хватает какой-то концепции.
Мысли высоко ценится
1 ответ
У меня есть реализация такой системы на JS/PHP. Мой подход состоит в том, чтобы сериализовать записи как на клиенте, так и на сервере, используя эталонную систему.
Например, несохраненный Foo1 имеет GUID eeffa3, а второй Foo ссылается на его id
ключ как {otherFooId: '@Foo#eeffa3[id]' }
Точно так же вы можете ссылаться на весь объект, как это
Foo#eefa3:{bars['@Baz#ffg4', '@Baz#ffg5']}
Теперь сериализатор на стороне клиента будет строить дерево отношений и атрибуты модели, как это
{
modelsToSave:[
'Foo#effe3':{
attribs:{name:'John', title:'Mr.'},
relations:{bars:['@Bar#ffg4']}
},
'Bar#ffg4':{
attribs:{id:5}
relations:{parentFoo:'@Foo#effe3'}
},
]
}
Как вы можете видеть в этом примере, я описал круговые отношения между несохраненными объектами в чистом JSON.
Ключевым моментом здесь является сохранение этих "записей" объектов в памяти на стороне клиента и никогда не изменять их GUID
Сервер может определить порядок сохранения, сохранив сначала записи без "родительских" зависимостей, а затем записи, которые зависят от этих родителей
После сохранения сервер вернет ту же карту ссылок, но теперь атрибуты будут также включать первичные ключи и внешние ключи.
JS дважды просматривает полученную карту (первый проход - просто обновить полученные сервером атрибуты, второй проход - ссылки на замещающие записи и ссылки на атрибуты на реальные записи и атрибуты).
Таким образом, есть 2 механизма для ссылки на запись, GUID на стороне клиента и PK на стороне сервера
При получении серверного JSON вы сопоставляете свой GUID с первичным ключом сервера