Подход к разрешению зависимостей и оптимистичным обновлениям в реагирующих приложениях

В архитектуре, где объекты имеют много сложных отношений, каковы некоторые поддерживаемые подходы к решению

  1. Разрешение зависимостей
  2. Оптимистичные Обновления

в реакции приложений?

Например, учитывая этот тип схемы:

```
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
```

Я не уверен, что лучший способ решить эту проблему

Текущие подходы, которые приходят на ум

  1. Есть пользовательские действия, которые выполняют координацию через обещания

    save(biz).then(_ => save(Bar).then(_ => save(firstFoo)).then(_ => save(second)

Недостатком здесь является то, что это довольно сложно, и число таких комбинаций будет продолжать расти

  1. Создайте помощника в ожидании / разрешении

    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 с первичным ключом сервера

Другие вопросы по тегам