Các cửa hàng thông lượng, hoặc các hành động (hoặc cả hai) có chạm vào các dịch vụ bên ngoài không?


122

Nếu các cửa hàng duy trì trạng thái của riêng họ và có khả năng gọi các dịch vụ mạng và lưu trữ dữ liệu làm như vậy ... trong trường hợp đó, các hành động chỉ là những người chuyển tin nhắn ngu ngốc,

-HOẶC LÀ-

... liệu các cửa hàng có phải là người nhận dữ liệu bất biến từ các hành động (và các hành động là những hành động tìm nạp / gửi dữ liệu giữa các nguồn bên ngoài? Lưu trữ trong trường hợp này sẽ hoạt động như các mô hình xem và có thể tổng hợp / lọc dữ liệu trước khi thiết lập trạng thái của riêng chúng dựa trên dữ liệu bất biến mà chúng được cung cấp bởi hành động.

Đối với tôi, dường như nó phải là cái này hay cái kia (chứ không phải là sự kết hợp của cả hai). Nếu vậy, tại sao cái này lại được ưu tiên / đề xuất hơn cái kia?


2
Bài đăng này có thể giúp code-experience.com/…
Markus-ipse

Đối với những người đánh giá các triển khai khác nhau của mẫu thông lượng, tôi thực sự khuyên bạn nên xem Redux github.com/rackt/redux Stores được triển khai dưới dạng các hàm thuần túy ở trạng thái hiện tại và phát ra phiên bản mới của trạng thái đó. Vì chúng hoạt động thuần túy nên câu hỏi liệu chúng có thể gọi các dịch vụ mạng và lưu trữ hay không sẽ nằm ngoài tầm tay của bạn: chúng không thể.
plaxdan

Câu trả lời:


151

Tôi đã thấy mô hình dòng chảy được triển khai theo cả hai cách và sau khi tự mình thực hiện cả hai cách (ban đầu theo cách tiếp cận cũ), tôi tin rằng các cửa hàng phải là người nhận dữ liệu từ các hành động và quá trình xử lý không đồng bộ của các lần ghi sẽ tồn tại trong người tạo hành động. (Các lần đọc Async có thể được xử lý theo cách khác .) Theo kinh nghiệm của tôi, điều này có một vài lợi ích, theo thứ tự quan trọng:

  1. Các cửa hàng của bạn trở nên hoàn toàn đồng bộ. Điều này làm cho logic cửa hàng của bạn dễ theo dõi hơn và rất dễ kiểm tra — chỉ cần khởi tạo cửa hàng với một số trạng thái nhất định, gửi cho nó một hành động và kiểm tra xem trạng thái có thay đổi như mong đợi hay không. Hơn nữa, một trong những khái niệm cốt lõi trong thông lượng là ngăn chặn việc gửi xếp tầng và ngăn nhiều lần gửi cùng một lúc; điều này rất khó thực hiện khi các cửa hàng của bạn xử lý không đồng bộ.

  2. Tất cả các yêu cầu hành động xảy ra từ người tạo hành động. Nếu bạn xử lý các hoạt động không đồng bộ trong các cửa hàng của mình và bạn muốn giữ cho các trình xử lý hành động của cửa hàng đồng bộ (và bạn nên để có được sự đảm bảo của một lần điều phối thông lượng), thì các cửa hàng của bạn sẽ cần phải kích hoạt thêm các hành động THÀNH CÔNG và THẤT BẠI để đáp ứng với sự không đồng bộ Chế biến. Thay vào đó, việc đưa những công văn này cho người tạo hành động giúp tách biệt công việc của người tạo hành động và cửa hàng; hơn nữa, bạn không cần phải tìm hiểu logic cửa hàng của mình để tìm ra các hành động đang được thực hiện từ đâu. Một hành động không đồng bộ điển hình trong trường hợp này có thể trông giống như thế này (thay đổi cú pháp của lệnh dispatchgọi dựa trên hương vị của thông lượng bạn đang sử dụng):

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

    Logic có thể bị trùng lặp trong các hành động khác nhau nên được trích xuất vào một mô-đun riêng biệt; trong ví dụ này, mô-đun đó sẽ SomeDataAccessLayerxử lý thực hiện yêu cầu Ajax thực tế.

  3. Bạn cần ít người tạo hành động hơn. Đây không phải là vấn đề lớn, nhưng rất vui nếu có. Như đã đề cập trong # 2, nếu các cửa hàng của bạn có xử lý điều phối hành động đồng bộ (và họ nên làm như vậy), bạn sẽ cần kích hoạt các hành động bổ sung để xử lý kết quả của các hoạt động không đồng bộ. Thực hiện các điều khoản trong trình tạo hành động có nghĩa là một người tạo hành động duy nhất có thể gửi cả ba loại hành động bằng cách xử lý kết quả của chính quyền truy cập dữ liệu không đồng bộ.


15
Tôi nghĩ điều bắt nguồn cuộc gọi api web (người tạo hành động so với cửa hàng) ít quan trọng hơn thực tế là lệnh gọi lại thành công / lỗi sẽ tạo ra một hành động. Vì vậy, luồng dữ liệu sau đó luôn là: hành động -> người điều phối -> lưu trữ -> lượt xem.
fishwebdev

1
Việc đặt logic yêu cầu thực tế trong một mô-đun API có tốt hơn / dễ kiểm tra hơn không? Vì vậy, mô-đun API của bạn chỉ có thể trả về một lời hứa mà bạn gửi từ đó. Người tạo hành động chỉ gửi đi dựa trên giải quyết / thất bại sau khi gửi hành động 'đang chờ xử lý' ban đầu. Câu hỏi vẫn còn là cách thành phần lắng nghe các 'sự kiện' này vì tôi không chắc rằng trạng thái yêu cầu sẽ ánh xạ đến trạng thái lưu trữ.
backdesk

@backdesk Đó chính xác là những gì tôi làm trong ví dụ trên: gửi một hành động đang chờ xử lý ban đầu ( "SOME_ACTION"), sử dụng một API để thực hiện một yêu cầu ( SomeDataAccessLayer.doSomething(userId)) trả về một lời hứa và trong hai .thenhàm, gửi các hành động bổ sung. Yêu cầu trạng thái có thể (nhiều hơn hoặc ít hơn) ánh xạ để lưu trữ trạng thái nếu ứng dụng cần biết về trạng thái của trạng thái. Bản đồ này tùy thuộc vào ứng dụng như thế nào (ví dụ: có thể mỗi nhận xét có một trạng thái lỗi riêng, một Facebook hoặc có thể có một thành phần lỗi toàn cầu)
Michelle Tilley

@MichelleTilley "một trong những khái niệm cốt lõi trong thông lượng là ngăn việc gửi xếp tầng và ngăn nhiều lần gửi cùng một lúc; điều này rất khó thực hiện khi các cửa hàng của bạn xử lý không đồng bộ." Đó là một điểm mấu chốt đối với tôi. Nói hay lắm.

51

Tôi đã tweet câu hỏi này cho các nhà phát triển tại Facebook và câu trả lời tôi nhận được từ Bill Fisher là:

Khi phản hồi tương tác của người dùng với giao diện người dùng, tôi sẽ thực hiện lệnh gọi không đồng bộ trong các phương thức của trình tạo hành động.

Nhưng khi bạn có một mã hoặc một số trình điều khiển không phải con người khác, cuộc gọi từ cửa hàng sẽ hoạt động tốt hơn.

Điều quan trọng là tạo một hành động trong lệnh gọi lại lỗi / thành công để dữ liệu luôn bắt nguồn từ các hành động


Trong khi điều này có ý nghĩa, bất kỳ ý tưởng tại sao a call from store works better when action triggers from non-human driver ?
SharpCoder

@SharpCoder Tôi đoán nếu bạn có mã đánh dấu trực tiếp hoặc thứ gì đó tương tự, bạn không thực sự cần phải kích hoạt hành động và khi bạn làm điều đó từ cửa hàng, bạn có thể phải viết ít mã hơn, vì cửa hàng có thể truy cập ngay trạng thái & phát ra một sự thay đổi.
Florian Wendelborn

8

Các cửa hàng phải làm mọi thứ, bao gồm cả việc tìm nạp dữ liệu và báo hiệu cho các thành phần rằng dữ liệu của cửa hàng đã được cập nhật. Tại sao? Bởi vì các hành động sau đó có thể nhẹ, dùng một lần và có thể thay thế mà không ảnh hưởng đến hành vi quan trọng. Tất cả các hành vi và chức năng quan trọng xảy ra trong cửa hàng. Điều này cũng ngăn chặn hành vi trùng lặp mà nếu không sẽ được sao chép trong hai hành động rất giống nhau nhưng khác nhau. Các cửa hàng là nguồn duy nhất của bạn (xử lý) sự thật.

Trong mọi triển khai Flux mà tôi đã thấy Các hành động về cơ bản là các chuỗi sự kiện được chuyển thành các đối tượng, giống như truyền thống bạn sẽ có một sự kiện có tên "anchor: click" nhưng trong Flux, nó sẽ được định nghĩa là AnchorActions.Clicked. Chúng thậm chí còn "ngớ ngẩn" đến mức hầu hết các triển khai đều có các đối tượng Dispatcher riêng biệt để thực sự gửi các sự kiện đến các cửa hàng đang lắng nghe.

Cá nhân tôi thích việc triển khai Flux của Reflux nơi không có đối tượng Dispatcher riêng biệt và đối tượng Action tự thực hiện việc điều phối.


chỉnh sửa: Flux của Facebook thực sự tìm nạp trong "trình tạo hành động" để họ sử dụng các hành động thông minh. Họ cũng chuẩn bị tải trọng bằng cách sử dụng các cửa hàng:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/actions/ChatMessageActionCreators.js#L27 (dòng 27 và 28)

Sau đó, lệnh gọi lại khi hoàn thành sẽ kích hoạt một hành động mới lần này với dữ liệu được tìm nạp dưới dạng tải trọng:

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

Vì vậy, tôi đoán đó là giải pháp tốt hơn.


Triển khai Reflux này là gì? Tôi chưa nghe nói về nó. Câu trả lời của bạn thật thú vị. Ý bạn là việc triển khai cửa hàng của bạn phải có logic để thực hiện các lệnh gọi API, v.v.? Tôi nghĩ rằng các cửa hàng chỉ nên nhận dữ liệu và chỉ cần cập nhật giá trị của chúng. Họ lọc các hành động cụ thể và cập nhật một số thuộc tính của cửa hàng của họ.
Jeremy D

Reflux là một biến thể nhỏ của Flux của Facebook: github.com/spoike/refluxjs Stores quản lý toàn bộ miền "Model" của ứng dụng của bạn, so với Actions / Dispatchers chỉ ghép và gắn mọi thứ lại với nhau.
Rygu

1
Vì vậy, tôi đã suy nghĩ về điều này nhiều hơn và đã (gần như) trả lời câu hỏi của riêng tôi. Tôi đã có thể thêm nó như một câu trả lời ở đây (để những người khác bỏ phiếu) nhưng có vẻ như tôi quá kém nghiệp dư trong stackoverflow để có thể đăng một câu trả lời. Vì vậy, đây là một liên kết: groups.google.com/d/msg/reactjs/PpsvVPvhBbc/BZoG-bFeOwoJ
plaxdan

Cảm ơn liên kết nhóm google, nó có vẻ thực sự thông tin. Tôi cũng yêu thích hơn mọi thứ đều thông qua người điều phối và một logic thực sự đơn giản trong cửa hàng, về cơ bản, cập nhật dữ liệu của họ. @Rygu Tôi sẽ kiểm tra trào ngược.
Jeremy D

Tôi đã chỉnh sửa câu trả lời của mình với một chế độ xem thay thế. Có vẻ như cả hai giải pháp đều khả thi. Tôi gần như chắc chắn sẽ chọn giải pháp của Facebook hơn những giải pháp khác.
Rygu

3

Tôi sẽ đưa ra một lập luận ủng hộ các Hành động "ngu ngốc".

Bằng cách đặt trách nhiệm thu thập dữ liệu chế độ xem trong Hành động của mình, bạn kết hợp Hành động với các yêu cầu dữ liệu của chế độ xem.

Ngược lại, các Hành động chung, mô tả rõ ràng ý định của người dùng hoặc một số chuyển đổi trạng thái trong ứng dụng của bạn, cho phép bất kỳ Cửa hàng nào phản hồi với Hành động đó chuyển đổi ý định thành trạng thái được thiết kế riêng cho các chế độ xem đã đăng ký.

Điều này có lợi cho nhiều Cửa hàng hơn, nhưng nhỏ hơn, chuyên biệt hơn. Tôi lập luận cho phong cách này bởi vì

  • điều này giúp bạn linh hoạt hơn trong cách các chế độ xem sử dụng dữ liệu Store
  • Cửa hàng "thông minh", chuyên dành cho các lượt xem sử dụng chúng, sẽ nhỏ hơn và ít được ghép nối cho các ứng dụng phức tạp hơn so với các Hành động "thông minh", nơi có nhiều lượt xem phụ thuộc vào

Mục đích của Cửa hàng là cung cấp dữ liệu cho các chế độ xem. Tên "Hành động" gợi ý cho tôi rằng mục đích của nó là mô tả sự thay đổi trong Ứng dụng của tôi.

Giả sử bạn phải thêm tiện ích con vào chế độ xem Trang tổng quan hiện có, hiển thị một số dữ liệu tổng hợp mới lạ mắt mà nhóm phụ trợ của bạn vừa triển khai.

Với Hành động "thông minh", bạn có thể cần phải thay đổi Hành động "làm mới bảng điều khiển" của mình để sử dụng API mới. Tuy nhiên, "Làm mới bảng điều khiển" theo nghĩa trừu tượng vẫn không thay đổi. Yêu cầu dữ liệu của chế độ xem của bạn là những gì đã thay đổi.

Với Hành động "ngu ngốc", bạn có thể thêm Cửa hàng mới để tiện ích con mới sử dụng và thiết lập nó để khi nhận được loại Hành động "làm mới trang tổng quan", nó sẽ gửi yêu cầu về dữ liệu mới và hiển thị tiện ích con mới khi nó đã sẵn sàng. Tôi hiểu rằng khi lớp xem cần nhiều hoặc nhiều dữ liệu khác nhau, những thứ tôi thay đổi chính là nguồn của dữ liệu đó: Cửa hàng.


2

bản demo flux- react -router- của gaeron có một biến thể tiện ích tuyệt vời của cách tiếp cận 'đúng'.

ActionCreator tạo ra một lời hứa từ một dịch vụ API bên ngoài, sau đó chuyển lời hứa và ba hằng số hành động cho một dispatchAsynchàm trong proxy / Điều phối viên mở rộng. dispatchAsyncsẽ luôn gửi hành động đầu tiên, ví dụ: 'GET_EXTERNAL_DATA' và khi lời hứa trả về, nó sẽ gửi 'GET_EXTERNAL_DATA_SUCCESS' hoặc 'GET_EXTERNAL_DATA_ERROR'.


1

Nếu bạn muốn một ngày nào đó có một môi trường phát triển có thể so sánh với những gì bạn thấy trong video nổi tiếng Phát minh trên nguyên tắc của Bret Victor , bạn nên sử dụng các cửa hàng câm chỉ là phép chiếu các hành động / sự kiện bên trong cấu trúc dữ liệu mà không có bất kỳ tác dụng phụ nào. Nó cũng sẽ hữu ích nếu các cửa hàng của bạn thực sự là thành viên của cùng một cấu trúc dữ liệu bất biến toàn cầu, như trong Redux .

Giải thích thêm tại đây: https://stackoverflow.com/a/31388262/82609

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.