Flux uygulamasında ajax talebi nerede yapılmalıdır?


194

Flux mimarisi ile bir reakt.js uygulaması oluşturuyorum ve nerede ve ne zaman sunucudan veri için bir istek yapılması gerektiğini anlamaya çalışıyorum. Bunun bir örneği var mı? (TODO uygulaması değil!)

Yanıtlar:


127

Ben eylem yaratıcıları zaman uyumsuz yazma işlemleri ve mağazada zaman uyumsuz okuma işlemleri koymak büyük bir savunucusuyum. Amaç, mağaza durumu değişiklik kodunu tamamen eşzamanlı eylem işleyicilerinde tutmaktır; bu onları akıl yürütmeyi ve ünite testini kolaylaştırır. Aynı uç noktaya (örneğin, çift okuma) aynı anda birden fazla isteği önlemek için, gerçek istek işlemeyi birden fazla isteği önlemek için vaatler kullanan ayrı bir modüle taşıyacağım; Örneğin:

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

Mağazadaki okumalar eşzamansız işlevler içeriyor olsa da, mağazaların kendilerini eşzamansız işleyicilerde güncellemedikleri, ancak bir eylemi tetiklediği ve yalnızca yanıt geldiğinde bir eylemi tetiklediği önemli bir uyarı vardır . Bu eylemin işleyicileri gerçek durum değişikliğini yapar.

Örneğin, bir bileşen şunları yapabilir:

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

Mağazanın belki de böyle bir yöntem uygulanmış olması gerekir:

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

Eylem yüklerinin içine söz vermeyi denedin mi? Birden fazla eylem göndermekten daha kolay başa
çıkabiliyorum

@SebastienLorber Benim için büyük akı çekme tüm durum güncellemelerini eşzamanlı bir kod yolunda ve açıkça yalnızca eylem gönderilerinin bir sonucu olarak tutmaktır , bu yüzden mağazalarda eşzamansızlığı önlerim.
Michelle Tilley

1
@Federico Bana göre "en iyi" çözümün ne olduğu belirsiz. Bekleyen zaman uyumsuz istek sayısını saymakla birlikte veri yükleme için bu stratejiyi deniyorum. Ne yazık ki fluxinşaattan sonra mağazalara enjekte edilir, bu nedenle başlatma yönteminde eylem almanın harika bir yolu yoktur. Yahoo'nun izomorofik akı kütüphanelerinden bazı iyi fikirler bulabilirsiniz; Bu Fluxxor v2'nin daha iyi desteklemesi gereken bir şey. Bu konuda daha fazla sohbet etmek isterseniz bana e-posta göndermekten çekinmeyin.
Michelle Tilley

1
data: resultolmalı data : data, değil mi? yok result. veri parametresini faydalı yüke ya da buna benzer bir şekilde yeniden adlandırmak daha iyi olabilir.
oligofren

2
Bu eski iş parçacığı çok yararlı buldum - özellikle Bill Fisher ve Jing Chen yorumları. Bu, @BinaryMuse'un, eylem oluşturucuda gönderimin gerçekleştiği küçük farkla önerdiğine çok yakın.
phillipwei

37

Fluxxor sahip bir örnek , bir API ile uyumsuz iletişim.

Bu blog yayını bunun hakkında konuşuyor ve React'in blogunda yer aldı.


Bunu, arka uçla ön uç yazılım senkronizasyonu hala bir acı olduğu için henüz net olarak cevaplanmayan çok önemli ve zor bir soru olarak görüyorum.

JSX bileşenlerinde API istekleri yapılmalı mı? Mağazalar? Başka yer?

Mağazalarda isteklerin gerçekleştirilmesi, 2 mağaza belirli bir işlem için aynı verilere ihtiyaç duyarsa, 2 benzer istekte bulunacakları anlamına gelir (mağazalar arasında gerçekten sevmediğim bağımlılıklar getirmedikçe )

Benim durumumda, Q sözlerini eylem yükü olarak koymak için çok kullanışlı buldum çünkü:

  • İşlemlerimin serileştirilmesine gerek yok (Bir olay günlüğünü tutmuyorum, olay kaynağının olay tekrar oynatma özelliğine ihtiyacım yok)
  • Farklı eylemler / olaylar (istek tetiklendi / istek tamamlandı / istek başarısız oldu) gereksinimini ortadan kaldırır ve eşzamanlı istekler tetiklendiğinde korelasyon kimlikleri kullanarak bunları eşleştirmek zorunda kalır.
  • Birden fazla mağazanın, mağazalar arasında herhangi bir bağımlılık yaratmadan aynı talebin tamamlanmasını dinlemesine izin verir (ancak bir önbellek katmanı eklemek daha iyi olabilir mi?)

Ajax kötüdür

Sanırım Ajax yakın gelecekte gittikçe daha az kullanılacak, çünkü akıl yürütmek çok zor. Doğru yol? Cihazları dağıtılmış sistemin bir parçası olarak düşünürsek, bu fikre ilk kez nereden geldiğimi bilmiyorum (belki bu ilham verici Chris Granger videosunda ).

Bunu düşün. Şimdi ölçeklenebilirlik için depolama motorları olarak nihai tutarlılığa sahip dağıtılmış sistemler kullanıyoruz (çünkü CAP teoremini yenemeyiz ve çoğu zaman kullanılabilir olmak istiyoruz). Bu sistemler birbirlerini yoklayarak senkronize etmezler (belki konsensüs işlemleri hariç?), Aksine dağıtılmış sistemin tüm üyelerini nihayetinde tutarlı hale getirmek için CRDT ve olay günlükleri gibi yapıları kullanırlar (üyeler aynı verilere, yeterli süre verilecek) .

Şimdi bir mobil cihaz veya tarayıcı hakkında düşünün. Ağ gecikmesi ve ağ bölümlendirmesinden muzdarip olabilecek yalnızca dağıtılmış sistemin bir üyesidir. (yani akıllı telefonunuzu metroda kullanıyorsunuz)

Ağ bölümü ve ağ hızına toleranslı veritabanları oluşturabilirsek (yani yalıtılmış bir düğüme yazma işlemleri gerçekleştirebiliriz), büyük olasılıkla bu kavramlardan esinlenerek çevrimdışı modun desteklediği iyi çalışan ön uç yazılımları (mobil veya masaüstü) oluşturabiliriz olmadan app kutusunun kullanılamaz özellikleri.

Veri tabanlarının, ön uç uygulamalarımızı mimarlık için nasıl çalıştığına gerçekten ilham vermemiz gerektiğini düşünüyorum. Dikkat edilmesi gereken bir şey, bu uygulamaların birbirlerine veri göndermek için POST ve PUT ve GET ajax istekleri gerçekleştirmemesi, ancak sonuç tutarlılığını sağlamak için olay günlüklerini ve CRDT'yi kullanmasıdır.

Öyleyse neden bunu ön uçta yapmıyorsunuz? Arka ucun bu yönde ilerlediğine dikkat edin, Kafka gibi araçlar büyük oyuncular tarafından kitlesel olarak benimsendi. Bu bir şekilde Olay Sağlama / CQRS / DDD ile de ilgilidir.

Kendinizi ikna etmek için Kafka yazarlarından bu harika makalelere göz atın:

Belki sunucuya komutlar göndererek ve Ajax isteklerini tetiklemek yerine bir sunucu olayları akışı (örnek için websockets aracılığıyla) alarak başlayabiliriz.

Ajax istekleri konusunda hiç bu kadar rahat olmamıştım. Biz tepki olarak geliştiriciler fonksiyonel programcı olma eğilimindedir. Bence gerçek hakikati aslında sunucu veritabanındayken ve "yerel" hakikat kaynağınız zaten güncel olmayabilirken, ön uç uygulamanızın "gerçek kaynağınız" olması gereken yerel veriler hakkında akıl yürütmenin zor olduğunu düşünüyorum aldığınızda ve bazı topallama Yenile düğmesine basmadıkça asla gerçek doğruluk değerinin kaynağına yaklaşmayacaktır ... Bu mühendislik mi?

Ancak, bazı açık nedenlerle böyle bir şey tasarlamak hala biraz zor:

  • Mobil / tarayıcı istemcinizin kaynakları sınırlıdır ve tüm verileri yerel olarak depolayamayabilir (bu nedenle bazen bir ajax isteği yoğun içerikle yoklama gerektirir)
  • İstemciniz dağıtılmış sistemin tüm verilerini görmemelidir, bu nedenle güvenlik nedeniyle aldığı olayları bir şekilde filtrelemek gerekir

3
Q vaatlerini eylemlerle kullanma örneği verebilir misiniz?
Matt Foxx Duncan

@MattFoxxDuncan, "olay günlüğünü" değiştirilemez hale getirdiği ve işlenmekte olan eylemlerde mağaza güncellemesini eşzamansız hale getirdiği için iyi bir fikir olduğundan emin değil, bu nedenle bazı dezavantajları var. kazan plakasını azaltın. Fluxxor ile muhtemelen böyle bir şey yapabilirsinizthis.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
Sebastien Lorber

AJAX argümanınıza tamamen katılmıyorum. Aslında okumak çok can sıkıcıydı. Yorumlarınızı okudunuz mu? Mağazalar, oyunlar, ciddi para kazandıran uygulamaları düşünün - hepsi API ve AJAX sunucu çağrıları gerektirir .. "Sunucusuz" veya bu tür bir şey istiyorsanız Firebase'e bakın, ancak AJAX en azından hiç kimsenin aynı fikirde olmadığını umuyorum mantık
TheBlackBenzKid

@TheBlackBenzKid Ajax'ın yıl içinde tamamen ortadan kalkacağını söylemiyorum (ve şu anda bir başlangıç ​​CTO'su olarak ajax istekleri üzerine web siteleri oluşturduğumdan emin olun), ancak muhtemelen kaybolacağını söylüyorum çünkü akış yerine yoklama ve yoklama gerektiren nihai tutarlılığı kaldıracak kadar iyi bir protokol değildir ve nihai tutarlılık, uygulamaların çevrimdışı olarak güvenilir bir şekilde çalışmasına izin veren şeydir (evet, yerel depolama ile bir şeyi kendiniz hackleyebilirsiniz, ancak sınırlı çevrimdışı kapasiteleriniz vardır veya uygulamanız çok basit). Sorun önbellekleme değil, bu önbelleği geçersiz kılıyor.
Sebastien Lorber

@TheBlackBenzKid Firebase, Meteor vb. Arkasındaki modeller yeterince iyi değil. Bu sistemlerin eşzamanlı yazıları nasıl işlediğini biliyor musunuz? nedensel tutarlılık / birleştirme stratejileri yerine son yazma-kazanma? Her ikisi de güvenilir olmayan bağlantılar üzerinde çalışırken bir uygulamada kolejinizin baskın çalışmasını göze alabilir misiniz? Ayrıca, bu sistemlerin yerel ve sunucu modellemelerini birbirine bağlama eğiliminde olduğunu unutmayın. Önemli derecede karmaşık, mükemmel bir çevrimdışı çalışan ve memnun bir Firebase kullanıcısı olduğunu ilan eden iyi bilinen ortak bir uygulama biliyor musunuz? Ben
Sebastien Lorber

20

İşlem yaratıcıları veya mağazalarda veri arayabilirsiniz. Önemli olan yanıtı doğrudan ele almak değil, hata / başarı geri aramasında bir eylem oluşturmaktır. Yanıtın doğrudan mağazada ele alınması daha kırılgan bir tasarıma yol açar.


9
Bunu daha ayrıntılı olarak açıklayabilir misiniz? Diyelim ki sunucudan ilk veri yüklemesi yapmam gerekiyor. Denetleyici görünümünde bir eylem INIT'i başlatırım ve Mağaza, bu eyleme yansıyan zaman uyumsuz başlatma işlemini başlatır. Şimdi, mağaza verileri aldığında, sadece değişiklik yayacağını, ancak bir eylem başlatmayacağı fikrine devam ediyorum. Bu nedenle, başlatma işleminden sonra bir değişiklik yayınlamak, görünümlere verileri mağazadan alabileceklerini bildirir. Başarılı bir yüklemeden sonra neden bir değişiklik yaymaya değil , başka bir eyleme başlamaya ihtiyaç duyuluyor ?! Teşekkürler
Jim-Y

Fisherwebdev, veri çağıran mağazalar hakkında, bunu yaparak, Flux paradigmasını kırmazsınız, veri aramak için düşünebileceğim tek 2 doğru yol aşağıdakileri kullanmaktır: 1. Veri yüklemek için Eylemler'i kullanarak bir önyükleme sınıfı kullanın 2 Görünümler, yine verileri yüklemek için Eylemler'i kullanma
Yotam

4
Veri aramak, veri almakla aynı şey değildir. @ Jim-Y: Sadece mağazadaki veriler gerçekten değiştikten sonra değişiklik yayınlamalısınız. Yotam: Hayır, mağazada veri aramak paradigmayı bozmaz. Veriler yalnızca eylemler yoluyla alınmalıdır, böylece tüm mağazalar uygulamaya giren yeni verilerden haberdar edilebilir. Bu yüzden bir mağazadaki verileri arayabiliriz, ancak yanıt geri geldiğinde, doğrudan işlemek yerine yeni bir işlem oluşturmamız gerekir. Bu, uygulamayı yeni özellik geliştirmeye esnek ve esnek tutar.
fisherwebdev

2

Fluxxor ajax örneğindeki Binary Muse örneğini kullanıyorum . İşte aynı yaklaşımı kullanan çok basit örneğim.

Basit bir ürün deposu bazı ürün eylemleri ve tüm ürün deposunda yapılan değişikliklere yanıt veren alt bileşenleri olan denetleyici görünümü bileşeni var . Örneğin , ürün kaydırma çubuğu , ürün listesi ve ürün arama bileşenleri.

Sahte Ürün İstemcisi

İşte gerçek bir son nokta dönen ürünleri çağırmak için değiştirebileceğiniz sahte müşteri.

var ProductClient = {

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

module.exports = ProductClient;

Ürün Mağazası

İşte Ürün Mağazası, açıkçası bu çok minimal bir mağaza.

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;

Şimdi AJAX isteğinde bulunan ve başarıya ulaşan ürün eylemleri, ürünleri mağazaya döndüren LOAD_PRODUCTS_SUCCESS eylemini başlatır.

Ürün İşlemleri

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;

Yani this.getFlux().actions.productActions.loadProducts()bu mağazayı dinleyen herhangi bir bileşenden çağrı yapmak ürünleri yükleyecektir.

Yine de addProduct(id) removeProduct(id), aynı modeli izleyerek vb ... gibi kullanıcı etkileşimlerine yanıt verecek farklı eylemler olduğunu hayal edebilirsiniz .

Umarım bu örnek biraz yardımcı olur, çünkü bunu uygulamak için biraz zor buldum, ancak kesinlikle mağazalarımı% 100 senkronize tutmaya yardımcı oldu.


2

Burada ilgili bir soruyu cevapladım: İç içe geçmiş api çağrılarını akı içinde nasıl ele alabilirim?

Eylemlerin, değişikliğe neden olan şeyler olması gerekmez. Dış dünyada bir değişikliğin uygulanmasını bildiren bir gazete gibi olmaları gerekiyor ve daha sonra uygulama bu haberlere yanıt veriyor. Mağazalar kendi içlerinde değişikliklere neden oluyor. Eylemler sadece onları bilgilendirir.

Flux'un yaratıcısı Bill Fisher https://stackoverflow.com/a/26581808/4258088

Temel olarak yapmanız gereken şey, eylemlere hangi verilere ihtiyacınız olduğunu belirtmektir. Mağaza işlem tarafından bilgilendirilirse, bazı verileri alması gerekip gerekmediğine karar vermelidir.

Mağaza, gerekli tüm verilerin toplanmasından / getirilmesinden sorumlu olmalıdır. Ancak, mağaza verileri istediğinde ve yanıtı aldıktan sonra, yanıtın doğrudan işlenmesi / kaydedilmesine karşılık, getirilen verilerle bir eylemin kendisini tetiklemesi gerektiğini belirtmek önemlidir.

Mağazalar şöyle görünebilir:

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

0

İşte benim almam: http://www.thedreaming.org/2015/03/14/react-ajax/

Umarım yardımcı olur. :)


8
kurallara göre aşağı oy verin. harici sitelere yanıt vermek bu siteyi daha az kullanışlı hale getirir ve daha düşük kaliteli yanıtlar vererek sitenin kullanışlılığını azaltır. harici URL'ler muhtemelen zamanla kırılacaktır. downvote bu arada çok iyi olan makalenin yararlılığı hakkında bir şey söylemiyor :)
oligofren

2
İyi yazı, ancak her yaklaşımın artılarını / eksilerini kısa bir özeti ekleyerek size oy verecektir. SO'da, cevabınızın özünü almak için bir bağlantıyı tıklamamız gerekmemelidir.
Cory House
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.