Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

А нужен ли put? #24

Open
zerkalica opened this issue Nov 19, 2016 · 4 comments
Open

А нужен ли put? #24

zerkalica opened this issue Nov 19, 2016 · 4 comments

Comments

@zerkalica
Copy link

zerkalica commented Nov 19, 2016

Начнем с того, что при сохранение атома выглядит странно: set(some) вызывает fetch. Для синхронизации это может и годится. Сохранению обычно

  1. предшествуют какие-то изменения в интерфейсе, индикатор, ошибки валидации и т.д. А put получается навязывает подход, когда мы это все делаем не прямо, а опосредованно после вызова set.
  2. Сохранение чего-то вообще не подразумевает наличие модели, POST запрос, сохранивший todo может ничего не вернуть кроме 200 кода успеха, получается делаем атом, только что б вытянуть ошибки и isPending. Атом становится своего рода контроллером, сервисом, а изначальная его идея - только реактивное распространение данных.
  3. Модель на сохранение может не соответствовать модели на загрузку, например могут быть какие-то метаданные только для сервера, логирование и т.д.
  4. Не всегда реакция на fetch - изменение стейта, это может быть переход на новый location, посылка еще одно запроса куда-либо и т.д.

Есть форма добавления Todo.
Данные формы и ее ошибки - 2 разных атома.
При сохранении данных надо проверить данные, обновить атом с ошибками, если ошибок нет - выполнить сохранение на сервер. Причем кроме todo, надо сохранить еще кучу данных, не имеющих отношения к нему, ну апи такое. После этого надо еще todos обновить на клиенте.

type Todo = {title?: string}

const todos = new cellx.Cell((push, fail, oldValue) => {
 fetch('/todos', {method: 'GET'})
  .then((todos) => push(todos))
  .catch(fail)

  return oldValue || []
})

const todoErrors = new cellx.Cell({})
const todoOnServer = new cellx.Cell({}, {
  put(t: {todos: Todo[], todo: Todo, counter: number, canAddEmpty: boolean}, push, fail) {
      fetch('/todo', {method: 'POST', body: JSON.stringify(t)})
        .then(() => {
             push()
             t.todos.set(t.todos.get().push(t.todo))
        })
        .catch(fail)
  }
})
const editableTodo = new cellx.Cell({})

function editTitle(title: string) {
  editableTodo.set({title})
}
let counter = 0
function saveTodo(canAddEmpty: boolean) {
  conts o = {}
  const todo = editableTodo.get()
  if (!canAddEmpty && !todo.title) {
    o.isErrors = true
    o.title = 'Title is empty'
  }
  todoErrors.set(o)
  if (!o.isError) {
     todoOnServer.set({todo, todos, counter: counter++, canAddEmpty})
  }
}
  1. Экшен saveTodo, который выполняет сохранение, формирует данные для передачи на сервер.
  2. Эти данные складываются из аргументов, с которым вызвали экшен (canAddEmpty) и контекста (editableTodo, counter, todos).
  3. А что если нет синглотнов и метод put ничего не знает о контексте. Получается, надо формировать объект всего-всего, что необходимо для передачи на сервер и, что важно, обновления стейта (нам же todos надо обновить)

В примере выше, видно, что todoOnServer - это уже не todo, а некая сущность с с todo, counter, canAddEmpty и на клиенте эта сущность нужна только для показа ошибок от сервера. При чтении у нас вообще отдельная коллекция из другого апи.

Вместо прямого fetch в saveTodo, мы упаковываем todo и canAddEmpty в один объект, сетим с ним атом, а атом уже делает fetch только ради состояния ошибок.

По мне, это и есть основная дырявость абстракции put: не очевидность сохранения, сценарий получается размазанным по saveTodo и put.

С прямым fetch в общем-то простой saveTodo получается, без лишних абстракций.

function saveTodo(canAddEmpty: boolean) {
  // ...
  if (!o.isError) {
      const p = fetch('/todo', {method: 'POST', body: JSON.stringify({todo: editableTodo.get(), counter: counter++ cannAddEmpty})})
        .then(() => {
             todos.set(todos.get().push(t.todo))
        })

        todoState.setPromise(p)
  }
}
@Riim
Copy link
Owner

Riim commented Nov 21, 2016

предшествуют какие-то изменения в интерфейсе, индикатор, ошибки валидации и т.д. А put получается навязывает подход, когда мы это все делаем не прямо, а опосредованно после вызова set.

в put не нужно устанавливать индикаторы, ошибки или что-то подобное. Он в первую очередь для обратной связи вычисляемой ячейки с ячейками из которых она вычисляется:

let firstName = cellx('Вася');
let lastName = cellx('Пупкин');

let fullName = cellx(() => firstName() + ' ' + lastName(), {
  put(value) {
    value = value.split(' ');
    firstName(value[0]);
    lastName(value[1]);
  }
});

console.log(fullName());
// => "Вася Пупкин"

fullName('Петя Запупкин'); // запись в вычисляемую ячейку

console.log(firstName());
// => "Петя"
console.log(lastName());
// => "Запупкин"

@zerkalica
Copy link
Author

Ага, т.е. это способ не сохранять все подряд, а только синхронизация, достаточно редкая задача.

@Riim
Copy link
Owner

Riim commented Nov 21, 2016

Да, синхронизация c мастер-ячейками или внешним хранилищем значения 1, 2. Для чего-то другого применять нет смысла.

@zerkalica
Copy link
Author

zerkalica commented Nov 21, 2016

У меня идея какая, для статуса сохранения идеально иметь 3 атома: данные, isPending, error.
Для загрузки сейчас не так: атом 1, а isPending, error самим атомом данных управляется.

Я хотел универсальный способ, как при сохранении. но, что б не светить pending и error атомы компоненту.

Нужна возможность статус и error хранить в отдельных атомах, управлять ими со-стороны. Но, в случае загрузки нужна возможность "просачивать" их через computable, как сейчас есть isPending, и error (только они создаются и обрабатываются внутри, а не со стороны). Интересно было бы, если б cellx мог так делать.

PS: Пожалуй с сохранением плохая идея "просачивать" атомы, т.к. они смешаются с isPending загрузки

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants