답변:
저는 액션 제작자에 비동기 쓰기 작업을 저장하고 상점에서 비동기 읽기 작업을 수행하는 데 큰 지지자입니다. 목표는 상점 상태 수정 코드를 완전히 동기식 조치 핸들러에 유지하는 것입니다. 따라서 추론하기 쉽고 단위 테스트가 간단합니다. 여러 개의 동시 요청을 동일한 엔드 포인트 (예 : 이중 판독)로 방지하기 위해 실제 요청 처리를 여러 요청을 방지하기 위해 약속을 사용하는 별도의 모듈로 옮길 것입니다. 예를 들면 다음과 같습니다.
class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}
상점의 읽기에는 비동기 함수가 포함되지만 상점이 비동기 핸들러에서 자체적으로 업데이트하지 않고 대신 조치가 실행되고 응답이 도착할 때만 조치가 실행된다는 중요한 경고 가 있습니다. 이 조치에 대한 핸들러는 실제 상태 수정을 수행합니다.
예를 들어, 구성 요소는 다음을 수행 할 수 있습니다.
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
시공 후에 상점에 주입되므로 initialize 메소드에서 조치를 취할 수있는 좋은 방법이 없습니다. Yahoo의 isomorophic flux libs에서 좋은 아이디어를 찾을 수 있습니다. 이것이 Fluxxor v2가 더 잘 지원해야하는 것입니다. 이것에 대해 더 많은 대화를 원하시면 언제든지 저에게 이메일을 보내주십시오.
data: result
이어야 data : data
합니까? 없습니다 result
. 데이터 매개 변수의 이름을 페이로드 또는 이와 유사한 것으로 바꾸는 것이 좋습니다.
Fluxxor에는 API와의 비동기 통신 예제 가 있습니다.
이 블로그 게시물 에 대해 이야기하고 React의 블로그에 실 렸습니다.
백엔드와의 프론트 엔드 소프트웨어 동기화가 여전히 고통스럽기 때문에 아직 명확하게 답변되지 않은 매우 중요하고 어려운 질문입니다.
JSX 컴포넌트에서 API 요청을해야합니까? 백화점? 다른 장소?
상점에서 요청을 수행한다는 것은 주어진 조치에 대해 2 개의 상점이 동일한 데이터를 필요로하는 경우 2 개의 유사한 요청을 발행한다는 것을 의미합니다 (상점 사이에 종속성을 도입하지 않는 한 실제로는 마음에 들지 않습니다 )
제 경우에는 Q 약속을 행동의 페이로드로 넣는 것이 매우 편리하다는 것을 알았습니다.
Ajax는 EVIL입니다
나는 Ajax가 추론하기가 매우 어렵 기 때문에 가까운 미래에 점점 더 적게 사용될 것이라고 생각합니다. 옳은 길? 분산 시스템의 일부로 장치를 고려할 때이 아이디어를 처음 발견 한 곳을 알지 못합니다 (이 영감을주는 Chris Granger 비디오에서 ).
생각 해봐 이제 확장 성을 위해 스토리지 엔진으로서 최종 일관성을 갖춘 분산 시스템을 사용합니다 ( CAP 정리를 이길 수없고 종종 사용 가능하기를 원하기 때문에). 이러한 시스템은 서로의 폴링을 통해 동기화되지 않고 (합의 작업 제외) 분산 시스템의 모든 구성원을 일관되게 만들기 위해 CRDT 및 이벤트 로그와 같은 구조를 사용합니다 (구성원은 충분한 시간이 주어지면 동일한 데이터로 수렴됩니다) .
이제 모바일 장치 나 브라우저가 무엇인지 생각해보십시오. 네트워크 대기 시간 및 네트워크 파티셔닝이 발생할 수있는 분산 시스템의 구성원 일뿐입니다. (즉, 지하철에서 스마트 폰을 사용하고 있습니다)
네트워크 파티션 및 네트워크 속도 허용 데이터베이스를 구축 할 수 있다면 (여전히 고립 된 노드에 대한 쓰기 작업을 수행 할 수 있음) 이러한 개념에서 영감을 얻은 프런트 엔드 소프트웨어 (모바일 또는 데스크탑)를 구축 할 수 있습니다. 응용 프로그램 기능을 사용할 수없는 상자의.
데이터베이스가 프론트 엔드 응용 프로그램을 아키텍처 화하는 방법에 대해 영감을 얻어야합니다. 주목할 점은 이러한 앱이 서로에게 데이터를 전송하기 위해 POST 및 PUT 및 GET ajax 요청을 수행하지 않고 이벤트 로그 및 CRDT를 사용하여 최종 일관성을 유지한다는 것입니다.
왜 프론트 엔드에서 그렇게하지 않습니까? 백엔드가 이미 그 방향으로 움직이고 있으며 Kafka와 같은 도구는 큰 플레이어가 대규모로 채택하고 있습니다. 이것은 어떻게 든 이벤트 소싱 / CQRS / DDD와 관련이 있습니다.
Kafka 작가의 멋진 기사를 확인하여 자신을 확신 시키십시오.
어쩌면 Ajax 요청을 발생시키는 대신 서버에 명령을 보내고 서버 이벤트 스트림 (예 : 웹 소켓을 통해)을 수신하는 것으로 시작할 수 있습니다.
나는 Ajax 요청에 결코 익숙하지 않았다. 우리가 반응함에 따라 개발자는 기능적인 프로그래머 인 경향이 있습니다. 프론트 엔드 애플리케이션의 "진리 소스"인 로컬 데이터에 대해 추론하기는 어렵다고 생각하지만 실제 진실 소스는 실제로 서버 데이터베이스에 있으며 "로컬"진실 소스는 이미 구식 일 수 있습니다. 당신이 그것을받을 때, 당신이 절름발이 새로 고침 버튼을 누르지 않으면 진정한 진실 가치의 근원으로 수렴하지 않을 것입니다 ...이 엔지니어링입니까?
그러나 몇 가지 명백한 이유로 이러한 것을 디자인하는 것은 여전히 어렵습니다.
this.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
활동 작성자 또는 상점에서 데이터를 호출 할 수 있습니다. 중요한 것은 응답을 직접 처리하지 않고 오류 / 성공 콜백에서 조치를 작성하는 것입니다. 상점에서 직접 응답을 처리하면 취성 설계가 더 복잡해집니다.
Fluxxor ajax example 에서 Binary Muse의 예제를 사용하고 있습니다. 다음은 동일한 접근법을 사용하는 매우 간단한 예입니다.
간단한 제품 저장소에 일부 제품 작업 과 제품 저장소의 변경 사항에 모두 응답하는 하위 구성 요소가있는 컨트롤러 뷰 구성 요소가 있습니다 . 예를 들어 product-slider , product-list 및 product-search components.
가짜 제품 클라이언트
다음은 실제 엔드 포인트 반품 제품 호출을 대체 할 수있는 가짜 클라이언트입니다.
var ProductClient = {
load: function(success, failure) {
setTimeout(function() {
var ITEMS = require('../data/product-data.js');
success(ITEMS);
}, 1000);
}
};
module.exports = ProductClient;
제품 판매점
여기에 제품 저장소가 있습니다. 분명히 이것은 매우 작은 저장소입니다.
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 호출을 플럭스로 처리하는 방법
행동은 변화를 일으키는 것으로 생각되지 않습니다. 그들은 외부 세계의 변화를 응용 프로그램에 알리는 신문과 같아야하며, 그런 다음 응용 프로그램이 그 뉴스에 응답합니다. 상점 자체가 변경됩니다. 행동은 그들에게 알려줍니다.
Flux 제작자 Bill Fisher 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/
희망이 도움이됩니다. :)