Yêu cầu ajax nên được thực hiện ở đâu trong ứng dụng Flux?


194

Tôi đang tạo một ứng dụng Reac.js với kiến ​​trúc thông lượng và tôi đang cố gắng tìm ra yêu cầu dữ liệu từ máy chủ ở đâu và khi nào. Có một ví dụ cho điều này. (Không phải ứng dụng TODO!)

Câu trả lời:


127

Tôi là một người ủng hộ lớn việc đưa các hoạt động ghi async vào các trình tạo hành động và các hoạt động đọc async trong cửa hàng. Mục tiêu là giữ cho mã sửa đổi trạng thái cửa hàng trong các trình xử lý hành động hoàn toàn đồng bộ; điều này làm cho chúng đơn giản để lý do và đơn giản để kiểm tra đơn vị. Để ngăn nhiều yêu cầu đồng thời đến cùng một điểm cuối (ví dụ: đọc hai lần), tôi sẽ chuyển việc xử lý yêu cầu thực tế sang một mô-đun riêng sử dụng lời hứa để ngăn chặn nhiều yêu cầu; ví dụ:

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

Trong khi đọc trong cửa hàng liên quan đến các chức năng không đồng bộ, có một cảnh báo quan trọng là các cửa hàng không tự cập nhật trong trình xử lý không đồng bộ, mà thay vào đó, kích hoạt một hành động và chỉ thực hiện một hành động khi có phản hồi. Người xử lý cho hành động này cuối cùng thực hiện sửa đổi trạng thái thực tế.

Ví dụ, một thành phần có thể làm:

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

Cửa hàng sẽ có một phương thức được thực hiện, có lẽ, một cái gì đó như thế này:

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

Bạn đã cố gắng đặt lời hứa trong tải trọng hành động? Tôi thấy việc giải quyết dễ dàng hơn là gửi nhiều hành động
Sebastien Lorber

@SebastienLorber Điều hấp dẫn lớn đối với tôi là giữ tất cả các cập nhật trạng thái trong một đường dẫn mã đồng bộ và chỉ rõ ràng là kết quả của việc gửi hành động, vì vậy tôi tránh sự không đồng bộ bên trong các cửa hàng.
Michelle Tilley

1
@Federico Tôi vẫn chưa rõ giải pháp "tốt nhất" là gì. Tôi đã thử nghiệm chiến lược này để tải dữ liệu kết hợp với đếm số lượng yêu cầu không đồng bộ nổi bật. Thật không may, fluxđược đưa vào các cửa hàng sau khi xây dựng, vì vậy không có cách nào tuyệt vời để có được các hành động trong phương thức khởi tạo. Bạn có thể tìm thấy một số ý tưởng hay từ libs thông lượng đẳng hướng của Yahoo; Đây là điều Fluxxor v2 nên hỗ trợ tốt hơn. Vui lòng gửi email cho tôi nếu bạn muốn trò chuyện về điều này nhiều hơn.
Michelle Tilley

1
data: resultnên data : data, phải không? không có là result. có lẽ tốt hơn để đổi tên param dữ liệu thành tải trọng hoặc một cái gì đó tương tự.
oligofren 8/03/2015

2
Tôi thấy chủ đề cũ này rất hữu ích - đặc biệt là ý kiến ​​của Bill Fisher và Jing Chen. Điều này rất gần với những gì @BinaryMuse đang đề xuất với sự khác biệt nhỏ mà việc gửi đi xảy ra trong trình tạo hành động.
phillipwei

37

Fluxxor có một ví dụ về giao tiếp không đồng bộ với API.

Bài đăng trên blog này đã nói về nó và đã được đăng trên blog của React.


Tôi thấy đây là một câu hỏi rất quan trọng và khó chưa được trả lời rõ ràng, vì đồng bộ hóa phần mềm frontend với phần phụ trợ vẫn còn là một nỗi đau.

Các yêu cầu API có nên được thực hiện trong các thành phần JSX không? Cửa hàng? Nơi khác?

Thực hiện các yêu cầu trong cửa hàng có nghĩa là nếu 2 cửa hàng cần cùng một dữ liệu cho một hành động nhất định, họ sẽ đưa ra 2 yêu cầu tương tự (trừ khi bạn giới thiệu phụ thuộc giữa các cửa hàng, điều mà tôi thực sự không thích )

Trong trường hợp của tôi, tôi đã thấy điều này rất tiện dụng để đặt lời hứa Q làm trọng tải hành động vì:

  • Hành động của tôi không cần phải tuần tự hóa (Tôi không giữ nhật ký sự kiện, tôi không cần tính năng phát lại sự kiện của nguồn cung cấp sự kiện)
  • Nó loại bỏ sự cần thiết phải có các hành động / sự kiện khác nhau (yêu cầu bị hủy / yêu cầu hoàn thành / yêu cầu không thành công) và phải khớp chúng bằng cách sử dụng id tương quan khi có thể hủy yêu cầu đồng thời.
  • Nó cho phép nhiều cửa hàng lắng nghe việc hoàn thành cùng một yêu cầu, mà không đưa ra bất kỳ sự phụ thuộc nào giữa các cửa hàng (tuy nhiên có thể tốt hơn để giới thiệu một lớp bộ nhớ đệm?)

Ajax là EVIL

Tôi nghĩ Ajax sẽ ngày càng ít được sử dụng trong tương lai gần bởi vì rất khó để lý do. Đúng cách? Xem xét các thiết bị như là một phần của hệ thống phân tán, tôi không biết lần đầu tiên tôi bắt gặp ý tưởng này (có thể trong video Chris Granger đầy cảm hứng này ).

Hãy suy nghĩ về nó. Bây giờ để có khả năng mở rộng, chúng tôi sử dụng các hệ thống phân tán có tính nhất quán cuối cùng làm công cụ lưu trữ (vì chúng tôi không thể đánh bại định lý CAP và thường chúng tôi muốn có sẵn). Các hệ thống này không đồng bộ hóa thông qua việc bỏ phiếu cho nhau (ngoại trừ có thể cho các hoạt động đồng thuận?) Mà sử dụng các cấu trúc như CRDT và nhật ký sự kiện để làm cho tất cả các thành viên của hệ thống phân tán cuối cùng (các thành viên sẽ hội tụ cùng một dữ liệu, trong một thời gian đủ) .

Bây giờ hãy nghĩ về một thiết bị di động hoặc một trình duyệt. Nó chỉ là một thành viên của hệ thống phân tán có thể bị ảnh hưởng bởi độ trễ mạng và phân vùng mạng. (tức là bạn đang sử dụng điện thoại thông minh của mình trên tàu điện ngầm)

Nếu chúng ta có thể xây dựng cơ sở dữ liệu phân vùng mạng và tốc độ mạng (ý tôi là chúng ta vẫn có thể thực hiện thao tác ghi vào một nút bị cô lập), chúng ta có thể xây dựng phần mềm frontend (di động hoặc máy tính để bàn) lấy cảm hứng từ các khái niệm này, hoạt động tốt với chế độ ngoại tuyến được hỗ trợ của hộp không có tính năng ứng dụng không có sẵn.

Tôi nghĩ rằng chúng ta nên thực sự truyền cảm hứng cho chính mình về cách cơ sở dữ liệu đang hoạt động để kiến ​​trúc các ứng dụng lối vào của chúng ta. Một điều cần chú ý là các ứng dụng này không thực hiện các yêu cầu POST và PUT và GET ajax để gửi dữ liệu cho nhau, mà sử dụng nhật ký sự kiện và CRDT để đảm bảo tính nhất quán cuối cùng.

Vậy tại sao không làm điều đó trên frontend? Lưu ý rằng phụ trợ đã di chuyển theo hướng đó, với các công cụ như Kafka được áp dụng rộng rãi bởi những người chơi lớn. Điều này cũng liên quan đến Nguồn cung cấp sự kiện / CQRS / DDD.

Kiểm tra những bài viết tuyệt vời này từ các tác giả Kafka để thuyết phục bản thân:

Có lẽ chúng ta có thể bắt đầu bằng cách gửi lệnh đến máy chủ và nhận một luồng các sự kiện máy chủ (thông qua websockets cho ví dụ), thay vì thực hiện các yêu cầu Ajax.

Tôi chưa bao giờ thấy thoải mái với các yêu cầu của Ajax. Khi chúng tôi React, các nhà phát triển có xu hướng trở thành các lập trình viên chức năng. Tôi nghĩ thật khó để lý giải về dữ liệu cục bộ được coi là "nguồn sự thật" của ứng dụng lối vào của bạn, trong khi nguồn sự thật thực sự có trên cơ sở dữ liệu máy chủ và nguồn sự thật "cục bộ" của bạn có thể đã lỗi thời khi bạn nhận được nó, và sẽ không bao giờ hội tụ đến nguồn thực của giá trị thật trừ khi bạn nhấn một số nút Làm mới khập khiễng ... Đây có phải là kỹ thuật không?

Tuy nhiên, vẫn còn một chút khó khăn để thiết kế một thứ như vậy vì một số lý do rõ ràng:

  • Ứng dụng khách trên thiết bị di động / trình duyệt của bạn có tài nguyên hạn chế và không nhất thiết phải lưu trữ tất cả dữ liệu cục bộ (do đó đôi khi yêu cầu bỏ phiếu với nội dung nặng yêu cầu ajax)
  • Máy khách của bạn không nên xem tất cả dữ liệu của hệ thống phân tán, do đó, nó yêu cầu bằng cách nào đó để lọc các sự kiện mà nó nhận được vì lý do bảo mật

3
Bạn có thể cung cấp một ví dụ về việc sử dụng lời hứa Q với các hành động không?
Matt Foxx Duncan

@MattFoxxDuncan không chắc chắn đó là một ý tưởng hay vì nó làm cho "nhật ký sự kiện" không thể xác định được và làm cho cửa hàng cập nhật không đồng bộ trên các hành động bị sa thải, vì vậy nó có một số nhược điểm. giảm nồi hơi. Với Fluxxor, bạn có thể có thể làm một cái gì đó nhưthis.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
Sebastien Lorber

Hoàn toàn không đồng ý về đối số AJAX của bạn. Trong thực tế, nó rất khó chịu để đọc. Bạn đã đọc nhận xét của bạn? Hãy nghĩ về các cửa hàng, trò chơi, ứng dụng kiếm tiền nghiêm túc - tất cả đều yêu cầu các cuộc gọi máy chủ API và AJAX .. hãy nhìn vào Firebase nếu bạn muốn "serverless" hoặc một cái gì đó có tính chất đó nhưng AJAX ở đây để nói rằng tôi hy vọng ít nhất không ai khác đồng ý với logic của bạn
TheBlackBenzKid

@TheBlackBenzKid Tôi không nói Ajax sẽ biến mất hoàn toàn trong năm nay (và chắc chắn rằng tôi vẫn đang xây dựng các trang web trên đầu các yêu cầu ajax hiện là CTO của một startup), nhưng tôi nói rằng nó có khả năng biến mất vì Đó không phải là một giao thức đủ tốt để xử lý tính nhất quán cuối cùng mà yêu cầu phát trực tuyến và không bỏ phiếu, và tính nhất quán cuối cùng là điều cho phép các ứng dụng hoạt động ngoại tuyến một cách đáng tin cậy (vâng, bạn có thể tự mình hack thứ gì đó với bộ lưu trữ cục bộ, nhưng bạn sẽ bị hạn chế khả năng ngoại tuyến, hoặc ứng dụng của bạn rất đơn giản). Vấn đề không phải là bộ nhớ đệm, nó làm mất hiệu lực bộ đệm đó.
Sebastien Lorber

@TheBlackBenzKid Các mô hình đằng sau Firebase, Meteor, v.v. không đủ tốt. Bạn có biết làm thế nào các hệ thống xử lý ghi đồng thời? chiến lược cuối cùng viết thay vì sự đồng thuận / chiến lược hợp nhất nhân quả? Bạn có thể đủ khả năng ghi đè công việc của đồng nghiệp của bạn trong một ứng dụng khi cả hai đang làm việc trên các kết nối không đáng tin cậy? Cũng lưu ý rằng các hệ thống này có xu hướng kết hợp rất nhiều mô hình cục bộ và máy chủ. Bạn có biết bất kỳ ứng dụng cộng tác nổi tiếng nào phức tạp đáng kể, hoạt động hoàn hảo ngoại tuyến, tuyên bố là người dùng Firebase hài lòng không? Tôi không
Sebastien Lorber

20

Bạn có thể gọi dữ liệu trong trình tạo hành động hoặc cửa hàng. Điều quan trọng là không xử lý trực tiếp phản hồi mà tạo ra một hành động trong cuộc gọi lại lỗi / thành công. Xử lý các phản ứng trực tiếp trong cửa hàng dẫn đến một thiết kế dễ vỡ hơn.


9
Bạn có thể giải thích điều này chi tiết hơn xin vui lòng? Nói rằng tôi cần phải tải dữ liệu ban đầu từ máy chủ. Trong giao diện điều khiển, tôi bắt đầu một hành động INIT và Cửa hàng bắt đầu khởi tạo không đồng bộ phản ánh hành động này. Bây giờ, tôi sẽ đi với ý tưởng, rằng khi Cửa hàng lấy dữ liệu, nó chỉ đơn giản sẽ phát ra thay đổi, nhưng không bắt đầu một hành động. Vì vậy, phát ra một thay đổi sau khi khởi tạo cho các quan điểm rằng họ có thể lấy dữ liệu từ cửa hàng. Tại sao không cần phải phát ra một thay đổi khi tải thành công, mà bắt đầu một hành động khác?! Cảm ơn
Jim-Y

Fisherwebdev, về các cửa hàng gọi dữ liệu, bằng cách đó, bạn không phá vỡ mô hình Flux, 2 cách duy nhất tôi có thể nghĩ đến để gọi dữ liệu là bằng cách sử dụng: 1. sử dụng lớp bootstrap sử dụng Hành động để tải dữ liệu 2 Lượt xem, một lần nữa sử dụng Tác vụ để tải dữ liệu
Yotam

4
Gọi dữ liệu không giống như nhận dữ liệu. @ Jim-Y: bạn chỉ nên phát ra thay đổi khi dữ liệu trong cửa hàng đã thực sự thay đổi. Yotam: Không, việc gọi dữ liệu trong cửa hàng không phá vỡ mô hình. Dữ liệu chỉ nên được nhận thông qua các hành động, để tất cả các cửa hàng có thể được thông báo bởi bất kỳ dữ liệu mới nào vào ứng dụng. Vì vậy, chúng tôi có thể gọi dữ liệu trong một cửa hàng, nhưng khi phản hồi trở lại, chúng tôi cần tạo một hành động mới thay vì xử lý trực tiếp. Điều này giữ cho ứng dụng linh hoạt và linh hoạt để phát triển tính năng mới.
fishingwebdev 18/03/2015

2

Tôi đã sử dụng ví dụ của Binary Muse từ ví dụ Fluxxor ajax . Đây là ví dụ rất đơn giản của tôi bằng cách sử dụng cùng một cách tiếp cận.

Tôi có một sản phẩm đơn giản lưu trữ một số hành động sản phẩm và thành phần xem bộ điều khiển có các thành phần phụ đáp ứng tất cả các thay đổi được thực hiện cho cửa hàng sản phẩm . Ví dụ sản phẩm thanh trượt , sản phẩm-listproduct-search linh kiện.

Khách hàng sản phẩm giả

Đây là ứng dụng khách giả mà bạn có thể thay thế để gọi một sản phẩm trả về điểm cuối thực tế.

var ProductClient = {

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

module.exports = ProductClient;

Cửa hàng sản phẩm

Đây là Cửa hàng sản phẩm, rõ ràng đây là một cửa hàng rất tối thiểu.

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;

Bây giờ các hành động của sản phẩm, thực hiện yêu cầu AJAX và thực hiện thành công hành động LOAD_PRODUCTS_SUCCESS trả lại sản phẩm cho cửa hàng.

Hoạt động sản phẩm

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;

Vì vậy, gọi this.getFlux().actions.productActions.loadProducts()từ bất kỳ thành phần nghe cửa hàng này sẽ tải các sản phẩm.

Bạn có thể tưởng tượng có các hành động khác nhau mặc dù sẽ phản ứng với các tương tác của người dùng như addProduct(id) removeProduct(id)vv ... theo cùng một mẫu.

Hy vọng rằng ví dụ này sẽ giúp một chút, vì tôi thấy điều này hơi khó thực hiện, nhưng chắc chắn đã giúp giữ cho các cửa hàng của tôi đồng bộ 100%.


2

Tôi đã trả lời một câu hỏi liên quan ở đây: Làm thế nào để xử lý các cuộc gọi api lồng nhau trong thông lượng

Hành động không được coi là những thứ gây ra thay đổi. Họ được cho là giống như một tờ báo thông báo về ứng dụng của một sự thay đổi trong thế giới bên ngoài, và sau đó ứng dụng này phản ứng với tin tức đó. Các cửa hàng gây ra thay đổi trong chính họ. Hành động chỉ cần thông báo cho họ.

Bill Fisher, người tạo ra Flux https://stackoverflow.com/a/26581808/4258088

Những gì bạn về cơ bản nên làm là, thông qua hành động những dữ liệu bạn cần. Nếu cửa hàng được thông báo bằng hành động, nó sẽ quyết định xem có cần lấy một số dữ liệu hay không.

Cửa hàng phải chịu trách nhiệm tích lũy / tìm nạp tất cả dữ liệu cần thiết. Tuy nhiên, điều quan trọng cần lưu ý là sau khi cửa hàng yêu cầu dữ liệu và nhận được phản hồi, nó sẽ tự kích hoạt một hành động với dữ liệu được tìm nạp, trái ngược với việc xử lý / lưu trực tiếp phản hồi của cửa hàng.

Một cửa hàng có thể trông giống như thế này:

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

Đây là của tôi về điều này: http://www.thedreaming.org/2015/03/14/react-ajax/

Mong rằng sẽ giúp. :)


8
downvote theo hướng dẫn. đặt câu trả lời trên các trang web bên ngoài làm cho trang web này ít hữu ích hơn và làm cho câu trả lời có chất lượng thấp hơn, làm giảm tính hữu ích của trang web. url bên ngoài có thể sẽ phá vỡ trong thời gian quá. downvote không nói gì về tính hữu ích của bài viết, điều này rất tốt :)
oligofren

2
Bài đăng tốt, nhưng thêm một bản tóm tắt ngắn về ưu / nhược điểm của từng phương pháp sẽ giúp bạn nâng cao tinh thần. Trên SO, chúng ta không cần phải nhấp vào một liên kết để có ý chính cho câu trả lời của bạn.
Nhà Cory
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.