ฉันกำลังสร้างแอปพลิเคชัน react.js ด้วยสถาปัตยกรรมของฟลักซ์และฉันพยายามหาว่าควรจะทำคำขอข้อมูลจากเซิร์ฟเวอร์ที่ไหนและเมื่อใด มีตัวอย่างใด ๆ สำหรับสิ่งนี้หรือไม่ (ไม่ใช่แอพพลิเคชั่นที่ต้องทำ!)
ฉันกำลังสร้างแอปพลิเคชัน react.js ด้วยสถาปัตยกรรมของฟลักซ์และฉันพยายามหาว่าควรจะทำคำขอข้อมูลจากเซิร์ฟเวอร์ที่ไหนและเมื่อใด มีตัวอย่างใด ๆ สำหรับสิ่งนี้หรือไม่ (ไม่ใช่แอพพลิเคชั่นที่ต้องทำ!)
คำตอบ:
ฉันเป็นผู้สนับสนุนหลักของการวางการดำเนินการเขียนแบบ async ในผู้สร้างแอ็คชั่นและการอ่านแบบ async ในร้าน เป้าหมายคือการเก็บรหัสการแก้ไขสถานะร้านค้าไว้ในตัวจัดการการกระทำแบบซิงโครนัสอย่างสมบูรณ์ สิ่งนี้ทำให้พวกเขาเข้าใจเหตุผลและทดสอบหน่วยได้ง่าย เพื่อป้องกันการร้องขอหลาย ๆ ครั้งพร้อมกันไปยังจุดปลายเดียวกัน (ตัวอย่างเช่นการอ่านสองครั้ง) ฉันจะย้ายการประมวลผลคำขอจริงไปยังโมดูลแยกต่างหากที่ใช้สัญญาเพื่อป้องกันการร้องขอหลายครั้ง ตัวอย่างเช่น:
class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}
ในขณะที่อ่านในร้านเกี่ยวข้องกับฟังก์ชั่นไม่ตรงกันมีข้อแม้สำคัญที่ร้านค้าไม่ปรับปรุงตัวเองในการขนย้ายวัสดุ async แต่แทนที่จะยิงการกระทำและเพียงยิงการกระทำเมื่อมาถึงการตอบสนอง ตัวจัดการสำหรับแอ็คชันนี้สิ้นสุดการทำการเปลี่ยนแปลงสถานะจริง
ตัวอย่างเช่นส่วนประกอบอาจทำ:
getInitialState() {
return { data: myStore.getSomeData(this.props.id) };
}
ร้านค้าจะมีวิธีดำเนินการบางทีอาจเป็นดังนี้:
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
ถูกฉีดเข้าไปในร้านค้าหลังการก่อสร้างดังนั้นจึงไม่มีวิธีที่ยอดเยี่ยมในการดำเนินการตามวิธีการเตรียมใช้งาน คุณอาจพบความคิดดีๆจาก libs isomorophic flux libs; นี่เป็นสิ่งที่ Fluxxor v2 น่าจะสนับสนุนได้ดีกว่า อย่าลังเลที่จะส่งอีเมลฉันหากคุณต้องการที่จะพูดคุยเกี่ยวกับเรื่องนี้มากขึ้น
data: result
ควรจะdata : data
ใช่มั้ย result
ไม่มี อาจดีกว่าที่จะเปลี่ยนชื่อพารามิเตอร์ข้อมูลเพื่อบรรจุข้อมูลหรืออะไรแบบนั้น
Fluxxor มีตัวอย่างของการสื่อสารแบบ async กับ API
โพสต์บล็อกนี้ได้พูดคุยเกี่ยวกับมันและได้รับการแนะนำในบล็อกของ React
ฉันพบว่านี่เป็นคำถามที่สำคัญและยากมากที่ยังไม่ได้รับคำตอบอย่างชัดเจนเนื่องจากการซิงโครไนซ์ซอฟต์แวร์ส่วนหน้ากับแบ็กเอนด์ยังคงเป็นปัญหา
คำขอ API ควรทำในส่วนประกอบ JSX หรือไม่ ร้านค้า? สถานที่อื่น ๆ ?
การดำเนินการตามคำขอในร้านค้าหมายความว่าหาก 2 ร้านค้าต้องการข้อมูลเดียวกันสำหรับการดำเนินการที่กำหนดพวกเขาจะออกคำขอที่คล้ายกัน 2 รายการ (เว้นแต่คุณจะแนะนำการพึ่งพาระหว่างร้านค้าซึ่งฉันไม่ชอบ )
ในกรณีของฉันฉันพบว่ามีประโยชน์มากที่จะให้สัญญา Q เป็นส่วนของการกระทำเพราะ:
อาแจ็กซ์ชั่วร้าย
ฉันคิดว่าอาแจ็กซ์จะใช้งานน้อยลงในอนาคตอันใกล้เพราะมันยากที่จะให้เหตุผล ทางที่ถูก? การพิจารณาอุปกรณ์เป็นส่วนหนึ่งของระบบกระจายฉันไม่รู้ว่าฉันเจอความคิดนี้ครั้งแรกที่ไหน (อาจเป็นในวิดีโอChris Granger ที่สร้างแรงบันดาลใจ )
ลองคิดดู ตอนนี้สำหรับความสามารถในการปรับขนาดเราใช้ระบบกระจายที่มีความสอดคล้องในที่สุดเป็นเครื่องมือเก็บข้อมูล (เพราะเราไม่สามารถเอาชนะทฤษฎีบท CAPและบ่อยครั้งที่เราต้องการให้มี) ระบบเหล่านี้ไม่ได้ทำการสำรวจความคิดเห็นของกันและกัน (ยกเว้นอาจจะเป็นฉันทามติการดำเนินการ) แต่ใช้โครงสร้างเช่น CRDT และบันทึกเหตุการณ์เพื่อให้สมาชิกทั้งหมดของระบบกระจายสอดคล้องกันในที่สุด (สมาชิกจะรวมกันเป็นข้อมูลเดียวกันให้เวลาเพียงพอ) .
ลองคิดดูว่าอุปกรณ์มือถือหรือเบราว์เซอร์คืออะไร มันเป็นเพียงสมาชิกของระบบกระจายที่อาจประสบความล่าช้าของเครือข่ายและการแบ่งเครือข่าย (เช่นคุณกำลังใช้สมาร์ทโฟนบนรถไฟใต้ดิน)
ถ้าเราสามารถสร้างพาร์ติชันเครือข่ายและฐานข้อมูลที่ยอมรับความเร็วของเครือข่าย (ฉันหมายความว่าเรายังสามารถทำการเขียนไปยังโหนดที่แยกได้) เราสามารถสร้างซอฟต์แวร์ส่วนหน้า (มือถือหรือเดสก์ท็อป) ซึ่งได้รับแรงบันดาลใจจากแนวคิดเหล่านี้ ของกล่องที่ไม่มีคุณสมบัติแอปไม่พร้อมใช้งาน
ฉันคิดว่าเราควรสร้างแรงบันดาลใจให้ตัวเองว่าฐานข้อมูลทำงานกับสถาปัตยกรรมแอปพลิเคชันส่วนหน้าของเราอย่างไร สิ่งหนึ่งที่ควรสังเกตคือแอพเหล่านี้ไม่ได้ทำการร้องขอ POST และ PUT และ GET ajax เพื่อส่งข้อมูลให้กัน แต่ควรใช้บันทึกเหตุการณ์และ CRDT เพื่อให้แน่ใจว่ามีความสอดคล้องกันในที่สุด
ดังนั้นทำไมไม่ทำเช่นนั้นในส่วนหน้า? ขอให้สังเกตว่าแบ็กเอนด์กำลังเคลื่อนไปในทิศทางนั้นด้วยเครื่องมือเช่นคาฟคาที่มีผู้เล่นรายใหญ่นำมาใช้อย่างหนาแน่น สิ่งนี้เกี่ยวข้องกับการจัดหากิจกรรม / CQRS / DDD ด้วยเช่นกัน
ตรวจสอบบทความที่ยอดเยี่ยมเหล่านี้จากผู้เขียน Kafka เพื่อโน้มน้าวตัวเอง:
บางทีเราสามารถเริ่มต้นด้วยการส่งคำสั่งไปยังเซิร์ฟเวอร์และรับกระแสเหตุการณ์เซิร์ฟเวอร์ (ผ่าน websockets สำหรับตัวอย่าง) แทนการยิงคำขอ Ajax
ฉันไม่เคยพอใจกับคำขอของ Ajax มาก่อน ในขณะที่เราตอบสนองผู้พัฒนาโปรแกรมมักจะทำงานเป็นโปรแกรมเมอร์ ฉันคิดว่ามันยากที่จะให้เหตุผลเกี่ยวกับข้อมูลท้องถิ่นที่ควรจะเป็น "แหล่งที่มาของความจริง" ของแอปพลิเคชั่นส่วนหน้าของคุณในขณะที่แหล่งที่แท้จริงของความเป็นจริงนั้นอยู่บนฐานข้อมูลเซิร์ฟเวอร์และแหล่งที่มา เมื่อคุณได้รับมันและจะไม่มาบรรจบกันกับแหล่งที่แท้จริงของค่าความจริงเว้นแต่คุณจะกดปุ่ม Refresh บางอย่าง ... วิศวกรรมนี้หรือไม่
อย่างไรก็ตามมันก็ยังยากที่จะออกแบบสิ่งนี้ด้วยเหตุผลบางอย่างที่ชัดเจน:
this.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
คุณสามารถสอบถามข้อมูลได้จากผู้สร้างแอ็คชั่นหรือร้านค้า สิ่งสำคัญคือไม่จัดการกับการตอบสนองโดยตรง แต่เพื่อสร้างการดำเนินการในการโทรกลับข้อผิดพลาด / ความสำเร็จ การจัดการการตอบสนองโดยตรงในร้านค้านำไปสู่การออกแบบที่เปราะบางมากขึ้น
ฉันได้ใช้ตัวอย่างเช่นไบนารี Muse จากตัวอย่าง Ajax Fluxxor นี่คือตัวอย่างง่ายๆของฉันโดยใช้วิธีการเดียวกัน
ฉันมีความเรียบง่ายผลิตภัณฑ์จัดเก็บบางการกระทำของผลิตภัณฑ์และการควบคุมมุมมององค์ประกอบซึ่งมีส่วนประกอบย่อยที่ตอบสนองทุกการเปลี่ยนแปลงที่เกิดขึ้นกับการจัดเก็บสินค้า ยกตัวอย่างเช่นผลิตภัณฑ์เลื่อน , สินค้ารายการและสินค้าที่มีการค้นหาชิ้นส่วน
ลูกค้าผลิตภัณฑ์ปลอม
นี่คือไคลเอนต์ปลอมซึ่งคุณสามารถทดแทนการโทรหาผลิตภัณฑ์ที่ส่งคืนปลายทางจริง
var ProductClient = {
load: function(success, failure) {
setTimeout(function() {
var ITEMS = require('../data/product-data.js');
success(ITEMS);
}, 1000);
}
};
module.exports = ProductClient;
ร้านค้าผลิตภัณฑ์
นี่คือ Product Store เห็นได้ชัดว่านี่เป็นร้านค้าที่น้อยมาก
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;
ตอนนี้การกระทำของผลิตภัณฑ์ซึ่งทำให้การร้องขอ AJAX และประสบความสำเร็จในการดำเนินการ LOAD_PRODUCTS_SUCCESS การดำเนินการส่งคืนผลิตภัณฑ์ไปที่ร้าน
การทำงานของผลิตภัณฑ์
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;
ดังนั้นการโทรthis.getFlux().actions.productActions.loadProducts()
จากองค์ประกอบใด ๆ ที่ฟังร้านนี้จะโหลดผลิตภัณฑ์
คุณสามารถจินตนาการว่ามีการกระทำที่แตกต่างกันซึ่งจะตอบสนองต่อการโต้ตอบของผู้ใช้เช่นaddProduct(id)
removeProduct(id)
อื่น ๆ ... ตามรูปแบบเดียวกัน
หวังว่าตัวอย่างจะช่วยได้นิดหน่อยเนื่องจากฉันพบว่ามันใช้ยากเล็กน้อย แต่ก็ช่วยให้ร้านค้าของฉันซิงโครนัสได้ 100%
ฉันตอบคำถามที่เกี่ยวข้องที่นี่: วิธีจัดการสาย api ซ้อนกันในฟลักซ์
การกระทำไม่ควรเป็นสิ่งที่ทำให้เกิดการเปลี่ยนแปลง พวกเขาควรจะเป็นเหมือนหนังสือพิมพ์ที่แจ้งการเปลี่ยนแปลงในโลกภายนอกจากนั้นแอปพลิเคชันจะตอบสนองต่อข่าวนั้น ร้านค้าทำให้เกิดการเปลี่ยนแปลงในตัวเอง การกระทำเพียงแจ้งพวกเขา
Bill Fisher ผู้สร้าง Flux https://stackoverflow.com/a/26581808/4258088
สิ่งที่คุณควรทำคือการระบุผ่านการกระทำที่คุณต้องการข้อมูล หากร้านค้าได้รับแจ้งจากการดำเนินการควรตัดสินใจว่าจะต้องดึงข้อมูลบางส่วนหรือไม่
ร้านค้าควรรับผิดชอบในการรวบรวม / ดึงข้อมูลที่จำเป็นทั้งหมด สิ่งสำคัญคือให้สังเกตว่าหลังจากที่ร้านค้าร้องขอข้อมูลและรับการตอบกลับแล้วควรเรียกการกระทำด้วยข้อมูลที่นำกลับมาใช้ซึ่งตรงข้ามกับที่จัดเก็บ / บันทึกการตอบกลับโดยตรง
ร้านค้าอาจมีลักษณะเช่นนี้:
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
}
}
นี่คือสิ่งที่ฉันใช้ในเรื่องนี้: http://www.thedreaming.org/2015/03/14/react-ajax/
หวังว่าจะช่วย :)