Saya membuat aplikasi react.js dengan arsitektur fluks dan saya mencoba mencari tahu di mana dan kapan permintaan untuk data dari server harus dibuat. Apakah ada contoh untuk ini? (Bukan aplikasi TODO!)
Saya membuat aplikasi react.js dengan arsitektur fluks dan saya mencoba mencari tahu di mana dan kapan permintaan untuk data dari server harus dibuat. Apakah ada contoh untuk ini? (Bukan aplikasi TODO!)
Jawaban:
Saya seorang pendukung besar menempatkan operasi tulis async di pembuat tindakan dan operasi membaca async di toko. Tujuannya adalah untuk menjaga kode modifikasi status toko dalam penangan tindakan yang sepenuhnya sinkron; ini membuatnya mudah untuk alasan dan mudah untuk unit test. Untuk mencegah beberapa permintaan simultan ke titik akhir yang sama (misalnya, membaca dua kali), saya akan memindahkan pemrosesan permintaan aktual ke modul terpisah yang menggunakan janji untuk mencegah beberapa permintaan; sebagai contoh:
class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}
Walaupun bacaan di toko melibatkan fungsi asinkron, ada peringatan penting bahwa toko tidak memperbarui diri dalam penangan async, tetapi memecat suatu tindakan dan hanya memecat suatu tindakan ketika respons datang. Penangan untuk tindakan ini akhirnya melakukan modifikasi keadaan aktual.
Sebagai contoh, sebuah komponen mungkin melakukan:
getInitialState() {
return { data: myStore.getSomeData(this.props.id) };
}
Toko akan menerapkan metode, mungkin, seperti ini:
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
}
}
flux
disuntikkan ke toko setelah konstruksi, jadi tidak ada cara yang bagus untuk mendapatkan tindakan dalam metode inisialisasi. Anda mungkin menemukan beberapa ide bagus dari lib fluks isomorofik Yahoo; ini adalah sesuatu yang harus didukung Fluxxor v2 dengan lebih baik. Jangan ragu untuk mengirim email kepada saya jika Anda ingin mengobrol lebih lanjut tentang ini.
data: result
seharusnya data : data
, kan? tidak ada result
. mungkin lebih baik untuk mengubah nama param data menjadi payload atau sesuatu seperti itu.
Fluxxor memiliki contoh komunikasi async dengan API.
Posting blog ini telah membicarakannya dan telah ditampilkan di blog React.
Saya menemukan ini pertanyaan yang sangat penting dan sulit yang belum dijawab dengan jelas, karena sinkronisasi perangkat lunak frontend dengan backend masih menyakitkan.
Haruskah permintaan API dibuat dalam komponen JSX? Toko? Tempat lain?
Melakukan permintaan di toko berarti bahwa jika 2 toko membutuhkan data yang sama untuk tindakan yang diberikan, mereka akan mengeluarkan 2 requets yang sama (kecuali jika Anda memperkenalkan dependensi antar toko, yang saya benar-benar tidak suka )
Dalam kasus saya, saya merasa ini sangat mudah untuk menempatkan janji Q sebagai payload tindakan karena:
Ajax adalah Jahat
Saya pikir Ajax akan semakin jarang digunakan dalam waktu dekat karena sangat sulit untuk dipikirkan. Jalan yang benar? Mengingat perangkat sebagai bagian dari sistem terdistribusi, saya tidak tahu dari mana saya pertama kali menemukan ide ini (mungkin dalam video Chris Granger yang menginspirasi ini ).
Pikirkan tentang itu. Sekarang untuk skalabilitas, kami menggunakan sistem terdistribusi dengan konsistensi akhirnya sebagai mesin penyimpanan (karena kami tidak dapat mengalahkan teorema CAP dan seringkali kami ingin tersedia). Sistem ini tidak disinkronkan melalui polling satu sama lain (kecuali mungkin untuk operasi konsensus?) Melainkan menggunakan struktur seperti CRDT dan log peristiwa untuk membuat semua anggota sistem terdistribusi akhirnya konsisten (anggota akan konvergen ke data yang sama, diberikan waktu yang cukup) .
Sekarang pikirkan tentang apa itu perangkat seluler atau browser. Itu hanya anggota dari sistem terdistribusi yang mungkin menderita latensi jaringan dan partisi jaringan. (yaitu Anda menggunakan ponsel cerdas Anda di kereta bawah tanah)
Jika kita dapat membangun partisi jaringan dan database toleran kecepatan jaringan (maksud saya kita masih dapat melakukan operasi tulis ke node yang terisolasi), kita mungkin dapat membangun perangkat lunak frontend (ponsel atau desktop) yang terinspirasi oleh konsep-konsep ini, yang bekerja dengan baik dengan mode offline yang didukung oleh kotak tanpa fitur aplikasi tidak tersedianya.
Saya pikir kita harus benar-benar menginspirasi diri kita sendiri tentang bagaimana database bekerja untuk arsitektur aplikasi frontend kita. Satu hal yang perlu diperhatikan adalah bahwa aplikasi ini tidak melakukan permintaan POST dan PUT dan DAPATKAN ajax untuk saling mengirim data, melainkan menggunakan log peristiwa dan CRDT untuk memastikan konsistensi akhirnya.
Jadi mengapa tidak melakukannya di frontend? Perhatikan bahwa backend sudah bergerak ke arah itu, dengan alat seperti Kafka diadopsi secara besar-besaran oleh pemain besar. Ini entah bagaimana terkait dengan Event Sourcing / CQRS / DDD juga.
Lihat artikel-artikel keren dari penulis Kafka untuk meyakinkan diri sendiri:
Mungkin kita bisa mulai dengan mengirim perintah ke server, dan menerima aliran peristiwa server (melalui websockets untuk contoh), alih-alih menembakkan permintaan Ajax.
Saya tidak pernah merasa nyaman dengan permintaan Ajax. Saat kami Bereaksi para pengembang cenderung menjadi programmer fungsional. Saya pikir sulit untuk beralasan tentang data lokal yang seharusnya menjadi "sumber kebenaran" aplikasi frontend Anda, sedangkan sumber sebenarnya sebenarnya ada di database server, dan sumber kebenaran "lokal" Anda mungkin sudah usang. ketika Anda menerimanya, dan tidak akan pernah konvergen ke sumber nilai kebenaran yang sebenarnya kecuali Anda menekan beberapa tombol Refresh yang lemah ... Apakah ini rekayasa?
Namun masih agak sulit untuk merancang hal seperti itu karena beberapa alasan yang jelas:
this.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
Anda dapat meminta data baik dari pembuat tindakan atau toko. Yang penting adalah untuk tidak menangani respons secara langsung, tetapi untuk membuat tindakan dalam panggilan balik kesalahan / sukses. Menangani respons langsung di toko mengarah ke desain yang lebih rapuh.
Saya telah menggunakan contoh Binary Muse dari contoh ajax Fluxxor . Ini adalah contoh sederhana saya menggunakan pendekatan yang sama.
Saya memiliki toko produk sederhana beberapa tindakan produk dan komponen tampilan-pengontrol yang memiliki sub-komponen yang semuanya menanggapi perubahan yang dibuat ke toko produk . Misalnya slider produk , daftar produk, dan komponen pencarian produk .
Klien Produk Palsu
Ini adalah klien palsu yang bisa Anda gantikan dengan menelepon produk pengembalian akhir aktual.
var ProductClient = {
load: function(success, failure) {
setTimeout(function() {
var ITEMS = require('../data/product-data.js');
success(ITEMS);
}, 1000);
}
};
module.exports = ProductClient;
Toko Produk
Inilah Product Store, jelas ini adalah toko yang sangat minim.
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;
Sekarang tindakan produk, yang membuat permintaan AJAX dan setelah sukses memecat, tindakan LOAD_PRODUCTS_SUCCESS mengembalikan produk ke toko.
Tindakan Produk
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;
Memanggil begitu this.getFlux().actions.productActions.loadProducts()
dari komponen apa pun yang mendengarkan toko ini akan memuat produk.
Anda dapat membayangkan memiliki tindakan yang berbeda yang akan menanggapi interaksi pengguna seperti addProduct(id)
removeProduct(id)
dll ... mengikuti pola yang sama.
Semoga contoh itu sedikit membantu, karena saya menemukan ini agak sulit untuk diterapkan, tetapi tentu saja membantu menjaga toko saya 100% sinkron.
Saya menjawab pertanyaan terkait di sini: Cara menangani panggilan api bersarang dalam fluks
Tindakan tidak seharusnya menjadi hal yang menyebabkan perubahan. Mereka seharusnya seperti surat kabar yang menginformasikan penerapan perubahan di dunia luar, dan kemudian aplikasi menanggapi berita itu. Toko-toko menyebabkan perubahan pada diri mereka sendiri. Tindakan hanya memberi tahu mereka.
Bill Fisher, pencipta Flux https://stackoverflow.com/a/26581808/4258088
Apa yang pada dasarnya harus Anda lakukan adalah, menyatakan melalui tindakan data apa yang Anda butuhkan. Jika toko mendapat informasi dari tindakan, ia harus memutuskan apakah perlu mengambil beberapa data.
Toko harus bertanggung jawab untuk mengumpulkan / mengambil semua data yang dibutuhkan. Penting untuk dicatat, bahwa setelah toko meminta data dan mendapat respons, itu harus memicu tindakan itu sendiri dengan data yang diambil, bertentangan dengan toko yang menangani / menyimpan respons secara langsung.
Toko bisa terlihat seperti ini:
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
}
}
Inilah pendapat saya tentang ini: http://www.thedreaming.org/2015/03/14/react-ajax/
Semoga itu bisa membantu. :)