it-swarm.com.ru

Где должен быть сделан запрос ajax в приложении Flux?

Я создаю приложениеact.js с потоковой архитектурой и пытаюсь выяснить, где и когда должен быть сделан запрос данных с сервера. Есть ли какой-нибудь пример для этого. (Не TODO приложение!)

191
Eniz Gülek

Я большой сторонник размещения асинхронных операций записи в создателях действий и асинхронных операций чтения в хранилище. Цель состоит в том, чтобы сохранить код модификации состояния хранилища в полностью синхронных обработчиках действий; это делает их простыми для рассуждения и простыми для модульного тестирования. Чтобы предотвратить несколько одновременных запросов к одной и той же конечной точке (например, двойное чтение), я перенесу фактическую обработку запроса в отдельный модуль, который использует обещания для предотвращения множественных запросов; например:

class MyResourceDAO {
  get(id) {
    if (!this.promises[id]) {
      this.promises[id] = new Promise((resolve, reject) => {
        // ajax handling here...
      });
    } 
    return this.promises[id];
  }
}

Хотя чтение в хранилище включает асинхронные функции, существует важное предостережение о том, что хранилища не обновляют себя в асинхронных обработчиках, а вместо этого запускают действие и только запускают действие, когда приходит ответ. Обработчики для этого действия заканчивают тем, что делали фактическое изменение состояния.

Например, компонент может сделать:

getInitialState() {
  return { data: myStore.getSomeData(this.props.id) };
}

В магазине был бы реализован метод, возможно, что-то вроде этого:

class Store {
  getSomeData(id) {
    if (!this.cache[id]) {
      MyResurceDAO.get(id).then(this.updateFromServer);
      this.cache[id] = LOADING_TOKEN;
      // LOADING_TOKEN is a unique value of some kind
      // that the component can use to know that the
      // value is not yet available.
    }

    return this.cache[id];
  }

  updateFromServer(response) {
    fluxDispatcher.dispatch({
      type: "DATA_FROM_SERVER",
      payload: {id: response.id, data: response}
    });
  }

  // this handles the "DATA_FROM_SERVER" action
  handleDataFromServer(action) {
    this.cache[action.payload.id] = action.payload.data;
    this.emit("change"); // or whatever you do to re-render your app
  }
}
125
Michelle Tilley

Fluxxor имеет пример асинхронного взаимодействия с API.

Это сообщение в блоге рассказывает об этом и было размещено в блоге React.


Я считаю, что это очень важный и сложный вопрос, на который пока нет четкого ответа, поскольку синхронизация программного обеспечения внешнего интерфейса с бэкэндом все еще является проблемой.

Должны ли запросы API выполняться в компонентах JSX? Магазины? Другое место?

Выполнение запросов в хранилищах означает, что если 2 хранилищам нужны одни и те же данные для заданного действия, они выдадут 2 одинаковых запроса (если вы не введете зависимости между хранилищами, что мне действительно не нравится )

В моем случае мне показалось очень удобным помещать обещания Q в качестве полезных данных действий, потому что:

  • Мои действия не должны быть сериализуемыми (я не веду журнал событий, мне не нужна функция воспроизведения событий при получении событий)
  • Это устраняет необходимость иметь разные действия/события (запрос запущен/запрос завершен/запрос не выполнен) и должен сопоставлять их с помощью идентификаторов корреляции, когда одновременные запросы могут быть запущены.
  • Это позволяет нескольким хранилищам прослушивать завершение одного и того же запроса, не вводя никакой зависимости между хранилищами (однако может быть лучше ввести уровень кэширования?)

Аякс - ЗЛО

Я думаю, что Ajax будет все меньше и меньше использоваться в ближайшем будущем, потому что об этом очень трудно рассуждать .... Правильный путь? Рассматривая устройства как часть распределенной системы Я не знаю, где я впервые наткнулся на эту идею (может быть, в этом вдохновляющее видео Криса Грейнджера ).

Думаю об этом. Теперь для масштабируемости мы используем распределенные системы с возможной согласованностью в качестве механизмов хранения (потому что мы не можем превзойти теорема CAP и часто мы хотим быть доступными). Эти системы не синхронизируются посредством опроса друг друга (за исключением, может быть, операций согласования?), А скорее используют структуры, такие как CRDT и журналы событий, чтобы в конечном итоге все члены распределенной системы были согласованными (участники будут сходиться к одним и тем же данным, если будет достаточно времени) ,.

Теперь подумайте, что такое мобильное устройство или браузер. Это просто член распределенной системы, который может страдать из-за задержки в сети и разбиения сети. (т.е. вы используете свой смартфон в метро)

Если мы сможем создать сетевые разделы и базы данных, допускающие скорость сети (я имею в виду, что мы все еще можем выполнять операции записи в изолированный узел), мы, вероятно, сможем создать программное обеспечение внешнего интерфейса (мобильное или настольное), основанное на этих концепциях, которое будет хорошо работать в автономном режиме, поддерживаемом из из коробки без возможности приложения недоступен.

Я думаю, что мы должны по-настоящему вдохновиться тем, как базы данных работают над архитектурой наших веб-приложений. Следует отметить, что эти приложения не выполняют запросы POST и PUT и GET ajax для отправки данных друг другу, а используют журналы событий и CRDT для обеспечения возможной согласованности. 

Так почему бы не сделать это на внешнем интерфейсе? Обратите внимание, что серверная часть уже движется в этом направлении, и такие инструменты, как Kafka, широко используются крупными игроками. Это как-то связано с Event Sourcing/CQRS/DDD тоже.

Посмотрите эти удивительные статьи от авторов Кафки, чтобы убедить себя:

Может быть, мы можем начать с отправки команд на сервер и получения потока серверных событий (например, через веб-сокеты) вместо запуска Ajax-запросов.

Мне никогда не было очень удобно с запросами Ajax. Как мы, разработчики React, склонны быть функциональными программистами. Я думаю, что трудно рассуждать о локальных данных, которые, как предполагается, являются вашим «источником правды» вашего веб-приложения, в то время как реальный источник правды фактически находится в базе данных сервера, а ваш «локальный» источник правды, возможно, уже устарел. когда вы его получите, и никогда не приблизитесь к реальному источнику значения истины, если не нажмете какую-нибудь хромую кнопку «Обновить» ... Это инженерия?

Однако все же немного сложно спроектировать такую ​​вещь по некоторым очевидным причинам:

  • Ваш мобильный/браузерный клиент имеет ограниченные ресурсы и не обязательно может хранить все данные локально (таким образом, иногда требуется опрос с использованием контента с большим количеством запросов ajax)
  • Ваш клиент не должен видеть все данные распределенной системы, поэтому ему необходимо каким-то образом фильтровать события, которые он получает по соображениям безопасности
37
Sebastien Lorber

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

20
fisherwebdev

Я использовал пример Binary Muse из примера Fluxor ajax . Вот мой очень простой пример, использующий тот же подход.

У меня простой продуктовый магазин немного действия продукта и контроллер вида компонент, который имеет подкомпоненты, которые все реагируют на изменения, внесенные в продуктовый магазин, Например Результат-слайдерсписок продуктов а также Результат-поиск компоненты.

Поддельный клиент продукта

Вот поддельный клиент, который вы могли бы заменить для вызова конечной точки, возвращающей продукты.

var ProductClient = {

  load: function(success, failure) {
    setTimeout(function() {
      var ITEMS = require('../data/product-data.js');
      success(ITEMS);
    }, 1000);
  }    
};

module.exports = ProductClient;

Продуктовый магазин

Вот Магазин Продуктов, очевидно, это очень минимальный магазин.

var Fluxxor = require("fluxxor");

var store = Fluxxor.createStore({

  initialize: function(options) {

    this.productItems = [];

    this.bindActions(
      constants.LOAD_PRODUCTS_SUCCESS, this.onLoadSuccess,
      constants.LOAD_PRODUCTS_FAIL, this.onLoadFail
    );
  },

  onLoadSuccess: function(data) {    
    for(var i = 0; i < data.products.length; i++){
      this.productItems.Push(data.products[i]);
    }    
    this.emit("change");
  },

  onLoadFail: function(error) {
    console.log(error);    
    this.emit("change");
  },    

  getState: function() {
    return {
      productItems: this.productItems
    };
  }
});

module.exports = store;

Теперь действия продукта, которые делают запрос AJAX и в случае успеха запускают действие LOAD_PRODUCTS_SUCCESS, возвращая продукты в магазин.

Действия продукта

var ProductClient = require("../fake-clients/product-client");

var actions = {

  loadProducts: function() {

    ProductClient.load(function(products) {
      this.dispatch(constants.LOAD_PRODUCTS_SUCCESS, {products: products});
    }.bind(this), function(error) {
      this.dispatch(constants.LOAD_PRODUCTS_FAIL, {error: error});
    }.bind(this));
  }    

};

module.exports = actions;

Поэтому вызов this.getFlux().actions.productActions.loadProducts() из любого компонента, прослушивающего этот магазин, загрузит продукты. 

Вы можете представить себе различные действия, которые будут реагировать на взаимодействие с пользователем, например addProduct(id)removeProduct(id) и т.д., По той же схеме.

Надеюсь, что этот пример немного поможет, так как я нашел это немного сложным для реализации, но, безусловно, помог сохранить мои магазины на 100% синхронными.

2
steven iseki

Я ответил на связанный с этим вопрос здесь: Как обрабатывать вложенные вызовы API в потоке

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

Билл Фишер, создатель Flux https://stackoverflow.com/a/26581808/4258088

То, что вы в основном должны делать, это указывать с помощью действий, какие данные вам нужны. Если магазин получает информацию о действии, он должен решить, нужно ли ему извлечь какие-либо данные. 

Хранилище должно отвечать за накопление/выборку всех необходимых данных. Важно отметить, что после того, как хранилище запросило данные и получило ответ, оно должно инициировать само действие с извлеченными данными, в отличие от хранилища, обрабатывающего/сохраняющего ответ напрямую. 

А магазины могут выглядеть примерно так:

class DataStore {
  constructor() {
    this.data = [];

    this.bindListeners({
      handleDataNeeded: Action.DATA_NEEDED,
      handleNewData: Action.NEW_DATA
    });
  }

  handleDataNeeded(id) {
    if(neededDataNotThereYet){
      api.data.fetch(id, (err, res) => {
        //Code
        if(success){
          Action.newData(payLoad);
        }
      }
    }
  }

  handleNewData(data) {
    //code that saves data and emit change
  }
}
2
MoeSattler

Вот мой взгляд на это: http://www.thedreaming.org/2015/03/14/react-ajax/

Надеюсь, это поможет. :)

0
Jason Walton