Akış depoları mı yoksa eylemler (veya her ikisi) harici hizmetlere mi dokunmalı?


122

Mağazalar kendi durumlarını koruyorlarsa ve bunu yaparken ağ ve veri depolama hizmetlerini arayabiliyorsa ... bu durumda eylemler sadece aptal mesaj ileticileridir,

-VEYA-

... mağazalar, eylemlerden gelen değişmez verilerin aptal alıcıları mı olmalı (ve eylemler, harici kaynaklar arasında veri getiren / gönderenler mi? Bu örnekte depolamak, görünüm modelleri olarak işlev görür ve bunları veriler, eylem tarafından beslendikleri değişmez verilere dayanarak kendi durum tabanlarını belirlemeden önce.

Bana öyle geliyor ki, biri ya da diğeri olmalı (her ikisinin bir karışımı yerine). Öyleyse, neden biri diğerine tercih ediliyor / öneriliyor?



Akı modelinin çeşitli uygulamalarını değerlendirenler için Redux github.com/rackt/redux sitesine bir göz atmanızı şiddetle tavsiye ederim Mağazalar, mevcut durumu alan ve bu durumun yeni bir sürümünü yayınlayan saf işlevler olarak uygulanır. Saf işlevler oldukları için, ağ ve depolama hizmetlerini arayıp arayamayacakları sorusu sizin elinizden alınır: yapamazlar.
plaxdan

Yanıtlar:


151

Akı modelinin her iki şekilde de uygulandığını gördüm ve her ikisini de kendim yaptıktan sonra (başlangıçta önceki yaklaşımı uyguladıktan sonra), mağazaların eylemlerden gelen aptal veri alıcıları olması gerektiğine ve yazma işlemlerinin eşzamansız işlenmesinin eylem yaratıcıları. ( Zaman uyumsuz okumalar farklı şekilde ele alınabilir .) Deneyimlerime göre, önem sırasına göre bunun birkaç faydası vardır:

  1. Mağazalarınız tamamen senkronize hale gelir. Bu, mağaza mantığınızı takip etmeyi ve test etmeyi çok daha kolay hale getirir - sadece belirli bir duruma sahip bir mağazayı somutlaştırın, ona bir eylem gönderin ve durumun beklendiği gibi değişip değişmediğini kontrol edin. Ayrıca, akıştaki temel kavramlardan biri, kademeli gönderimleri önlemek ve aynı anda birden fazla gönderimi önlemektir; Mağazalarınız eşzamansız işlem yaptığında bunu yapmak çok zordur.

  2. Tüm eylem gönderimleri, eylem yaratıcılarından gerçekleşir. Mağazalarınızda eşzamansız işlemler yapıyorsanız ve mağazalarınızın eylem işleyicilerini eşzamanlı tutmak istiyorsanız (ve akış tek gönderim garantilerini almak için yapmanız gerekir), eşzamansız işlemlere yanıt olarak mağazalarınızın ek BAŞARI ve BAŞARISIZ eylemleri gerçekleştirmesi gerekecektir. işleme. Bu gönderileri eylem oluşturuculara koymak, bunun yerine eylem oluşturucuların ve mağazaların işlerini ayırmaya yardımcı olur; dahası, eylemlerin nereden gönderildiğini anlamak için mağaza mantığınızı araştırmanıza gerek yoktur. Bu durumda tipik bir eşzamansız eylem şuna benzer görünebilir ( dispatchkullandığınız akışın türüne göre çağrıların sözdizimini değiştirin ):

    someActionCreator: function(userId) {
      // Dispatch an action now so that stores that want
      // to optimistically update their state can do so.
      dispatch("SOME_ACTION", {userId: userId});
    
      // This example uses promises, but you can use Node-style
      // callbacks or whatever you want for error handling.
      SomeDataAccessLayer.doSomething(userId)
      .then(function(newData) {
        // Stores that optimistically updated may not do anything
        // with a "SUCCESS" action, but you might e.g. stop showing
        // a loading indicator, etc.
        dispatch("SOME_ACTION_SUCCESS", {userId: userId, newData: newData});
      }, function(error) {
        // Stores can roll back by watching for the error case.
        dispatch("SOME_ACTION_FAIL", {userId: userId, error: error});
      });
    }

    Aksi takdirde, çeşitli eylemler arasında kopyalanabilecek mantık, ayrı bir modüle çıkarılmalıdır; bu örnekte, SomeDataAccessLayergerçek Ajax isteğini yerine getiren modül olacaktır .

  3. Daha az aksiyon oluşturucuya ihtiyacınız var. Bu daha az önemli, ama olması güzel. # 2'de belirtildiği gibi, mağazalarınızda eşzamanlı eylem gönderme yönetimi varsa (ve olmalıdır), eşzamansız işlemlerin sonuçlarını işlemek için fazladan eylemler başlatmanız gerekir. Eylem oluşturucularda gönderimleri yapmak, tek bir eylem oluşturucunun eşzamansız veri erişiminin sonucunu işleyerek üç eylem türünü de gönderebileceği anlamına gelir.


15
Bence web api çağrısını neyin başlattığı (eylem oluşturucuya karşı mağaza), başarı / hata geri aramasının bir eylem oluşturması gerektiği gerçeğinden daha az önemli. Dolayısıyla, veri akışı her zaman şu şekildedir: action -> dispatcher -> store -> views.
fisherwebdev

1
Gerçek istek mantığını bir API modülüne koymak daha iyi / daha kolay test edilebilir mi? Yani API modülünüz, gönderdiğiniz bir sözü döndürebilir. Eylem oluşturucu, ilk "beklemede" eylemini gönderdikten sonra çözüme / başarısızlığa göre gönderir. Geriye kalan soru, istek durumunun depolama durumunu eşleştirmesi gerektiğinden emin olmadığım için bileşenin bu 'olayları' nasıl dinlediğidir.
backdesk

@backdesk Yukarıdaki örnekte tam olarak yaptığım şey bu: ilk bekleyen eylemi gönder ( "SOME_ACTION"), SomeDataAccessLayer.doSomething(userId)bir söz veren bir istek yapmak için bir API kullan ( ) ve iki .thenişlevde ek eylemler gönder. Uygulamanın durumun durumu hakkında bilgi sahibi olması gerekiyorsa istek durumu (az ya da çok) durumu depolamak için eşleyebilir. Bu haritaların uygulamaya nasıl bağlı olduğu (örneğin, her yorumun ayrı bir hata durumu, bir Facebook veya belki bir genel hata bileşeni olabilir)
Michelle Tilley,

@MichelleTilley "Akıştaki temel kavramlardan biri, kademeli gönderimleri önlemek ve aynı anda birden fazla gönderimi önlemektir; mağazalarınız eşzamansız işlem yaptığında bunu yapmak çok zordur." Bu benim için kilit nokta. İyi söyledin.

51

Bu soruyu Facebook'taki geliştiricilere tweetledim ve Bill Fisher'dan aldığım cevap şuydu:

Bir kullanıcının kullanıcı arayüzüyle etkileşimine yanıt verirken, eylem oluşturucu yöntemlerinde zaman uyumsuz çağrıyı yapardım.

Ancak bir hisse senedi veya başka bir insan olmayan sürücünüz olduğunda, mağazadan gelen bir çağrı daha iyi çalışır.

Önemli olan hata / başarı geri aramasında bir eylem oluşturmaktır, böylece veriler her zaman eylemlerden kaynaklanır


Bu mantıklı olsa da, neden olduğuna dair bir fikriniz var a call from store works better when action triggers from non-human driver mı?
SharpCoder

@SharpCoder Sanırım canlı bir ticker veya benzeri bir şeyiniz varsa, gerçekten bir eylemi başlatmanıza gerek yok ve bunu mağazadan yaptığınızda, mağaza duruma anında erişebildiğinden muhtemelen daha az kod yazmanız gerekir. & bir değişiklik yayar.
Florian Wendelborn

8

Mağazalar, veri getirme ve mağazanın verilerinin güncellendiğine dair bileşenlere sinyal verme dahil her şeyi yapmalıdır. Neden? Çünkü eylemler, önemli davranışları etkilemeden hafif, tek kullanımlık ve değiştirilebilir olabilir. Mağazada tüm önemli davranış ve işlevler gerçekleşir. Bu ayrıca, aksi takdirde çok benzer ancak farklı iki eylemde kopyalanacak olan davranışın tekrarlanmasını da önler. Mağazalar, gerçeğin (ele alma) tek kaynağınızdır.

Gördüğüm her Flux uygulamasında Eylemler temelde nesnelere dönüştürülmüş olay dizeleridir, örneğin geleneksel olarak "çapa: tıklandı" adında bir olayınız olur, ancak Flux'da AnchorActions.Clicked olarak tanımlanır. Hatta o kadar "aptaldırlar ki" çoğu uygulamada olayları dinleyen mağazalara göndermek için ayrı Dispatcher nesneleri vardır.

Kişisel olarak Reflux'un ayrı Dispatcher nesnelerinin olmadığı ve Action nesnelerinin gönderimi kendilerinin yaptığı Flux uygulamasını seviyorum.


edit: Facebook'un Flux'ı aslında "aksiyon yaratıcılarını" getiriyor, bu yüzden akıllı eylemler kullanıyorlar. Ayrıca, mağazaları kullanarak yükü hazırlarlar:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/actions/ChatMessageActionCreators.js#L27 (satır 27 ve 28)

Tamamlandığında geri arama, bu sefer yük olarak getirilen verilerle yeni bir işlemi tetikler:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/utils/ChatWebAPIUtils.js#L51

Sanırım bu daha iyi bir çözüm.


Bu Reflü uygulaması nedir? Ben duymadım. Cevabınız ilginç. Mağaza uygulamanızın API çağrıları vb. Yapmak için mantığa sahip olması gerektiğini mi söylüyorsunuz? Mağazaların sadece veri alması ve değerlerini güncellemesi gerektiğini düşündüm. Belirli eylemleri filtreler ve mağazalarının bazı özelliklerini günceller.
Jeremy D

Reflux , Facebook'un Flux'ının küçük bir varyasyonudur: github.com/spoike/refluxjs Mağazalar, uygulamanızın tüm "Model" alanını yönetir, yalnızca nesneleri bir araya getirip yapıştıran Eylemler / Göndericiler.
Rygu

1
Bu yüzden bunu biraz daha düşünüyordum ve (neredeyse) kendi sorumu cevapladım. Bunu buraya bir cevap olarak eklerdim (başkalarının oy vermesi için) ama görünüşe göre stackoverflow'da henüz bir cevap veremeyecek kadar karma fakirim. İşte bir bağlantı: groups.google.com/d/msg/reactjs/PpsvVPvhBbc/BZoG-bFeOwoJ
plaxdan

Google grubu bağlantısı için teşekkürler, gerçekten bilgilendirici görünüyor. Ayrıca, dağıtıcıdan geçen her şeyin daha çok hayranıyım ve mağazadaki gerçekten basit bir mantık, temelde verilerini güncellemek, hepsi bu. @Rygu Reflü kontrol edeceğim.
Jeremy D

Cevabımı alternatif bir görünümle düzenledim. Görünüşe göre her iki çözüm de mümkün. Neredeyse kesinlikle Facebook'un çözümünü diğerlerine tercih ederim.
Rygu

3

"Aptalca" Eylemler lehine bir argüman sunacağım.

Eylemlerinize görünüm verilerini toplama sorumluluğunu yükleyerek, Eylemlerinizi görünümlerinizin veri gereksinimleriyle birleştirirsiniz.

Bunun aksine, kullanıcının amacını veya uygulamanızdaki bazı durum geçişlerini açıklayıcı bir şekilde açıklayan genel Eylemler, bu Eyleme yanıt veren herhangi bir Mağazanın amacı, kendisine abone olan görünümler için özel olarak uyarlanmış duruma dönüştürmesine olanak tanır.

Bu, daha çok sayıda, ancak daha küçük, daha uzmanlaşmış Mağazalara katkıda bulunur. Bu tarz için tartışıyorum çünkü

  • Bu, görünümlerin Mağaza verilerini nasıl tükettiği konusunda size daha fazla esneklik sağlar
  • Onları tüketen görünümler için özelleştirilmiş "akıllı" mağazalar, karmaşık uygulamalar için potansiyel olarak birçok görünümün bağlı olduğu "akıllı" İşlemlerden daha küçük ve daha az bağlantılı olacaktır.

Bir Mağazanın amacı, görünümlere veri sağlamaktır. "Eylem" adı bana, amacının Uygulamamdaki bir değişikliği tanımlamak olduğunu gösteriyor.

Mevcut bir Gösterge Tablosu görünümüne, arka uç ekibinizin yeni kullanıma sunmuş olduğu bazı güzel yeni toplu verileri gösteren bir pencere öğesi eklemeniz gerektiğini varsayalım.

"Akıllı" İşlemlerle, yeni API'yi kullanmak için "panoyu yenile" İşleminizi değiştirmeniz gerekebilir. Ancak, soyut anlamda "Gösterge tablosunun yenilenmesi" değişmedi. Görüşlerinizin veri gereksinimleri değişen şeydir.

"Aptalca" İşlemlerle, yeni widget'ın kullanması için yeni bir Mağaza ekleyebilir ve onu "yenileme panosu" Eylem türünü aldığında, yeni veriler için bir istek gönderecek ve yeni widget hazır olduğunda. Görünüm katmanı daha fazla veya farklı veriye ihtiyaç duyduğunda, değiştirdiğim şeylerin o verinin kaynakları olması bana mantıklı geliyor: Depolar.


2

gaeron'un flux-react-yönlendirici-demosu , 'doğru' yaklaşımın güzel bir fayda varyasyonuna sahiptir.

ActionCreator, harici bir API hizmetinden bir söz oluşturur ve ardından söz konusu vaadi ve üç eylem sabitini dispatchAsyncproxy / genişletilmiş Dağıtıcıdaki bir işleve geçirir . dispatchAsyncher zaman ilk eylemi, örneğin 'GET_EXTERNAL_DATA' gönderir ve söz geri döndüğünde, 'GET_EXTERNAL_DATA_SUCCESS' veya 'GET_EXTERNAL_DATA_ERROR' gönderir.


1

Bir gün, Bret Victor'un ünlü Inventing on Principle videosunda gördüklerinize benzer bir geliştirme ortamına sahip olmak istiyorsanız , herhangi bir yan etki olmaksızın, bir veri yapısı içindeki eylemlerin / olayların bir yansıması olan aptal mağazaları tercih etmelisiniz. Mağazalarınızın Redux gibi aynı küresel değişmez veri yapısının üyesi olmasının da yardımı olur .

Burada daha fazla açıklama: https://stackoverflow.com/a/31388262/82609

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.