2015-01-31 23 views
5

Tôi đang xây dựng một ứng dụng Flux bằng MartyJS (khá gần với "vanilla" Flux và sử dụng cùng một điều phối cơ bản). Nó chứa các cửa hàng với một mối quan hệ phụ thuộc vốn có. Ví dụ: UserStore theo dõi người dùng hiện tại và InstanceStore theo dõi các phiên bản dữ liệu do người dùng hiện tại sở hữu. Dữ liệu cá thể được lấy từ một API không đồng bộ.AJAX trong thông lượng: Làm mới các cửa hàng khi thay đổi trạng thái phụ thuộc

Câu hỏi đặt ra là phải làm gì với trạng thái của InstanceStore khi người dùng thay đổi.

Tôi đã tin tưởng (ví dụ đọc câu trả lời của @fisherwebdev trên SO) rằng nó phù hợp nhất để thực hiện các yêu cầu AJAX trong chức năng tạo tác vụ và có kết quả AJAX "thành công" trong một hành động. cửa hàng để thay đổi.

Vì vậy, để tìm nạp người dùng (tức là đăng nhập), tôi đang thực hiện cuộc gọi AJAX trong chức năng tạo tác vụ và khi giải quyết, tôi sẽ gửi một hành động RECEIVE_USER với người dùng dưới dạng tải trọng. Các UserStore lắng nghe điều này và cập nhật trạng thái của nó cho phù hợp.

Tuy nhiên, tôi cũng cần phải tìm nạp lại tất cả dữ liệu trong InstanceStore nếu người dùng bị thay đổi.

Lựa chọn 1: Tôi có thể nghe RECEIVE_USER trong InstanceStore, và nếu nó là một người dùng mới, kích hoạt một yêu cầu AJAX, do đó tạo ra một hành động, nó sẽ gây ra các InstanceStore để cập nhật. Vấn đề với điều này là nó cảm thấy giống như các hành động xếp tầng, mặc dù về mặt kỹ thuật nó không đồng bộ nên người điều phối có lẽ sẽ cho phép nó.

Lựa chọn 2: Một cách khác sẽ cho InstanceStore lắng nghe để thay đổi các sự kiện được phát ra bởi UserStore và làm điệu nhảy yêu cầu hành động đó, nhưng điều này cảm thấy sai lầm quá.

Tùy chọn 3: Cách thứ ba là để người tạo hành động dàn xếp hai cuộc gọi AJAX và gửi hai hành động riêng biệt. Tuy nhiên, bây giờ người tạo hành động phải biết rất nhiều về cách các cửa hàng liên quan đến nhau.

Một trong những câu trả lời trong Where should ajax request be made in Flux app? làm cho tôi nghĩ tùy chọn 1 là đúng, nhưng tài liệu thông lượng cũng ngụ ý rằng các cửa hàng kích hoạt hành động không tốt.

Trả lời

0

Tùy chọn 1 có vẻ là lựa chọn tốt nhất về mặt khái niệm với tôi. Có 2 cuộc gọi API riêng biệt, vì vậy bạn có 2 bộ sự kiện.

Đó là rất nhiều sự kiện trong một số lượng nhỏ mã, nhưng Flux luôn dựa vào cách tiếp cận Action-> Store-> View chuẩn, đơn giản. Một khi bạn làm một cái gì đó thông minh (như tùy chọn 2), bạn đã thay đổi điều đó. Nếu các nhà phát triển khác không còn có thể giả định rằng bất kỳ luồng Hành động nào cũng hoạt động giống hệt nhau, bạn đã mất một lợi ích lớn của Flux.

Nó sẽ không phải là cách tiếp cận ngắn nhất trong mã mặc dù. MartyJS trông giống như nó sẽ có một chút neater hơn so với thư viện Flux của Facebook ít nhất!

Một tùy chọn khác; nếu thông tin đăng nhập phải luôn làm mới InstanceStore, tại sao không có lệnh gọi API đăng nhập bao gồm tất cả dữ liệu InstanceStore?

(Và tiếp tục, tại sao có 2 cửa hàng riêng biệt?Họ có vẻ rất mạnh mẽ cùng một trong hai cách, và không có lý do bạn không thể vẫn thực hiện cuộc gọi đến API InstanceStore mà không cần đăng nhập lại gọi điện thoại anyway)

+0

Lý do cho hai cửa hàng là tất cả các dữ liệu được gắn với người sử dụng bằng cách nào đó (các dữ liệu cơ bản là một đồ thị), do đó bạn có kết thúc với một khổng lồ lấy ở đầu và một đơn , cửa hàng nguyên khối, hoặc bạn phải có phụ thuộc cửa hàng. – optilude

1

Điều gì đó giống như tùy chọn 3 có vẻ là giải pháp sạch nhất với tôi, theo sau là tùy chọn 1 Lý do của tôi:

Tùy chọn 2 lệch theo cách dự kiến ​​xử lý sự phụ thuộc giữa các cửa hàng (waitfor) và bạn phải kiểm tra sau mỗi sự kiện thay đổi để tìm ra sự kiện nào phù hợp và cái nào có thể bỏ qua hoặc bắt đầu sử dụng nhiều loại sự kiện; nó có thể khá lộn xộn.

Tôi nghĩ tùy chọn 1 là khả thi; dưới dạng Bill Fisher remarked trong bài đăng bạn đã liên kết, bạn có thể thực hiện các cuộc gọi API từ bên trong các cửa hàng miễn là dữ liệu kết quả được xử lý bằng cách gọi các Tác vụ mới. Nhưng OK không nhất thiết có ý nghĩa lý tưởng và bạn có thể đạt được sự tách biệt tốt hơn về mối quan tâm và giảm tầng nếu bạn có thể thu thập tất cả các cuộc gọi API và bắt đầu hành động ở một nơi (tức là ActionCreators). Và điều đó phù hợp với tùy chọn 3.

Tuy nhiên, bây giờ người tạo hành động phải biết rất nhiều về cách cửa hàng liên quan đến nhau.

Như tôi thấy, người tạo hành động không cần biết gì về những gì các cửa hàng đang làm. Nó chỉ cần đăng nhập vào một người dùng và sau đó lấy dữ liệu liên quan đến người dùng. Cho dù điều này được thực hiện thông qua một hoặc hai cuộc gọi API, chúng được kết hợp chặt chẽ và hợp lý trong phạm vi của một người tạo hành động. Khi người dùng đăng nhập và dữ liệu thu được, bạn có thể kích hoạt hai hành động (ví dụ: LOGGED_IN, GOT_USER_DATA) hoặc thậm chí chỉ là một hành động chứa tất cả dữ liệu cần thiết cho cả hai. Dù bằng cách nào, các hành động chỉ là lặp lại những gì các cuộc gọi API đã làm, và nó lên đến các cửa hàng để quyết định phải làm gì với nó.

Tôi khuyên bạn nên sử dụng một hành động đơn lẻ để cập nhật cả hai cửa hàng, vì đây là trường hợp sử dụng hoàn hảo cho waitfor: khi một hành động kích hoạt trình xử lý trong cả hai cửa hàng, bạn có thể yêu cầu InstanceStore đợi xử lý của UserStore hoàn thành trước Trình xử lý của InstanceStore thực hiện. Nó sẽ trông giống như sau:

UserStore.dispatchToken = AppDispatcher.register(function(payload) { 
    switch (payload.actionType) { 

    case Constants.GOT_USER_DATA: 

     ...(handle UserStore response)... 

     break; 

    ... 
    } 
}); 

... 

InstanceStore.dispatchToken = AppDispatcher.register(function(payload) { 
    switch (payload.actionType) { 

    case Constants.GOT_USER_DATA: 

     AppDispatcher.waitFor([UserStore.dispatchToken]); 

     ...(handle InstanceStore response)... 

     break; 

    ... 
    } 
}); 
0

Tôi thường sử dụng lời hứa để giải quyết tình huống như vậy. Ví dụ:

// UserAction.js 
var Marty  = require('marty'); 
var Constants = require('../constants/UserConstants'); 
var vow  = require('vow'); 

module.exports = Marty.createActionCreators({ 
    ... 

    handleFormEvent: function (path, e) { 
     var dfd = vow.defer(); 
     var prom = dfd.promise(); 
     this.dispatch(Constants.CHANGE_USER, dfd, prom); 
    } 
}); 


// UserStore.js 
var Marty  = require('marty'); 
var Constants = require('../constants/UserConstants'); 

module.exports = Marty.createStore({ 
    id: 'UserStore', 

    handlers: { 
     changeUser  : UserConstants.CHANGE_USER 
    }, 


    changeUser: function (dfd, __) { 
     $.ajax(/* fetch new user */) 
      .then(function (resp) { 
       /* do what you need */ 
       dfd.resolve(resp); 
      }); 
    } 
}); 



// InstanceStore.js 
var Marty  = require('marty'); 
var UserConstants = require('../constants/UserConstants'); 

module.exports = Marty.createStore({ 
    id: 'InstanceStore', 

    handlers: { 
     changeInstanceByUser : UserConstants.CHANGE_USER 
    }, 


    changeInstanceByUser: function (__, prom) { 
     prom.then(function (userData) { 
      /* OK, user now is switched */ 

      $.ajax(/* fetch new instance */) 
       .then(function (resp) { ... }); 
    } 
}); 
Các vấn đề liên quan