Flux:从 AJAX 向组件返回值
Posted
技术标签:
【中文标题】Flux:从 AJAX 向组件返回值【英文标题】:Flux: return values from AJAX to the component 【发布时间】:2014-12-14 14:37:49 【问题描述】:我正在开发简单的 Flux+Reactjs 应用程序,在我的商店里有:
var ProfileStore = merge(EventEmitter.prototype,
/**
* Get the entire collection of Profiles.
* @return object
*/
getAll: function()
//ajax call to mongolab
var url = "https://api.mongolab.com/api/1/databases/bar/collections/profiles?apiKey=foo-"
var jsPromise = Promise.resolve($.ajax(url));
jsPromise.then(function(response)
return response;
);
,
emitChange: function()
this.emit(CHANGE_EVENT);
,
/**
* @param function callback
*/
addChangeListener: function(callback)
this.on(CHANGE_EVENT, callback);
,
/**
* @param function callback
*/
removeChangeListener: function(callback)
this.removeListener(CHANGE_EVENT, callback);
);
然后在我的组件中:
var ProfileApp = React.createClass(
getInitialState: function()
return
allProfiles: ProfileStore.getAll()
;
,
);
当我在 getAll() 函数中使用 console.log() 时,我可以看到结果,但没有任何东西传递给我的组件,是否有任何关于如何解决此问题的指针?
【问题讨论】:
在您的商店中进行异步调用并不总是最好的解决方案,因为正如您所注意到的那样,它使您更难推断您的状态发生了什么。我建议阅读以下文章,该文章描述了使用通量处理异步请求的更好方法:code-experience.com/… 【参考方案1】:其他人指出了您的代码中与 Promise 相关的问题。但是,您尝试在商店中执行的操作的另一个问题是您尝试直接处理响应,而不是调度新操作。
在 Flux 中,数据应始终源自操作。函数getAll()
应该只返回本地存储的allProfiles
,类似于 andrewkshim 建议的,但没有 XHR。
相反,将您尝试执行的操作分解为以下类型的两个操作:
PROFILES_REQUEST_GET
:这是由用户单击按钮或任何导致发出请求的原因创建的——它会启动 XHR 请求。
PROFILES_REQUEST_SUCCESS
:这是由 XHR 的成功回调创建的操作。此操作包含新数据,并且商店可以相应地填充其allProfiles
。
【讨论】:
上面的代码是您尝试初始化应用程序的方式吗?如果是这样,只需调用引导模块中的数据,然后在成功回调中创建一个操作,类似于我在回答中描述的内容。 感谢您的反馈,您提到在 Flux 中,数据应始终源自操作,在我的情况下,我想立即加载组件呈现的配置文件,而不是响应操作,方法和你上面建议的一样吗? 重写了应用程序并遵循了flux-chat应用程序的代码这里是要点gist.github.com/johnwesonga/316b26760e2be043bbb1现在工作得很好【参考方案2】:使用 Flux 的设置要求您以不同的方式思考数据流动的方式。您可以做的是设置您的商店,以便首先包含对allProfiles
的引用,即undefined
(或null
或您喜欢的任何指定的“空”值),然后在@987654326 时更新@ 被调用:
var allProfiles; // the reference to your profile data
var ProfileStore = merge(EventEmitter.prototype,
getAll: function()
var thisStore = this;
var url = "YOUR MONGO URL"
var jsPromise = Promise.resolve($.ajax(url));
jsPromise.then(function(response)
allProfiles = response
this.emitChange();
);
return allProfiles;
// other methods omitted to save space
我应该指出你在这里使用的承诺是不正确的。 then
函数返回另一个承诺,因此您将 allProfiles
设置为承诺,而不是集合。在上面的示例中,我们返回对配置文件数据的引用,该引用将在 AJAX 调用完成后更新。数据更新后,存储会发出更改,让所有侦听器知道他们也应该更新。
在您的组件中,您可以将其设置为侦听您的ProfileStore
上的CHANGE_EVENT
,以便在ProfileStore
的数据更改时更新其状态。但是请注意,一开始,allProfiles
数据将为空,因此我们需要向用户传达我们正在加载数据:
var ProfileApp = React.createClass(
updateAllProfiles: function ()
this.setState(
allProfiles: ProfileStore.getAll()
);
,
getInitialState: function ()
return
allProfiles: ProfileStore.getAll()
,
componentDidMount: function()
ProfileStore.addChangeListener(this.updateAllProfiles);
,
componentWillUnmount: function ()
ProfileStore.removeChangeListener(this.updateAllProfiles)
,
render: function ()
var profiles;
if (this.state.allProfiles)
// you'll need to figure out how you want to render the profiles
// the line below will likely not be enough
profiles = this.state.allProfiles;
else
profiles = 'Loading...';
return <div id='profiles'>profiles</div>;
);
我在 JSFiddle 上做了一个非常人为的例子。由于环境的限制,我不得不想出几个模拟的hack,但我希望你能修改这个例子,更好地了解发生了什么:http://jsfiddle.net/berh6gxs/2/
我还掩盖了很多细节(例如,您可能希望在 ProfileApp
组件上实现 shouldComponentUpdate
方法,以便仅在数据实际更改时重新渲染),但我感觉到了这些细节对回答手头的问题不太重要。我之所以提到这一点,是因为您无法接受我在这里所说的并立即想出一个完美的解决方案。
我还建议研究 Flux 的第三方实现。雅虎提出了一个非常好的:https://github.com/yahoo/flux-examples
黑客愉快!
【讨论】:
【参考方案3】:这段代码:
jsPromise.then(function(response)
return response;
);
没有做我认为你认为的事情。它等待jsPromise
解析,并使用响应调用回调,并且从回调返回的任何内容都将成为从jsPromise.then
返回的new promise 的已解析值。查看 this javascript Promises guide 了解有关 Promise 工作原理的更多信息。
至于您的问题:简而言之,您不能从异步操作中返回值;你总是不得不求助于回调。例如:
var ProfileStore = merge(EventEmitter.prototype,
// getAll returns a Promise that resolves to all the profiles
getAll: function()
var url = "..."
return Promise.resolve($.ajax(url));
,
// ...
);
var ProfileApp = React.createClass(
getInitialState: function()
return
allProfiles: [] // initially we have no profiles
// could also have some "loading" sentinel, etc
;
,
componentDidMount: function()
// Then we ask for all the profiles and *asynchronously*
// set the state so the component updates.
ProfileStore.getAll().then(function(response)
this.setState(allProfiles: response);
.bind(this));
);
【讨论】:
本例中,store如何知道ajax调用(响应对象)返回的数据? @nilgun 我不太明白你的问题,但上面fisherwebdev的回答可能会有所帮助以上是关于Flux:从 AJAX 向组件返回值的主要内容,如果未能解决你的问题,请参考以下文章
我无法在 C# 中使用 Jquery 和 Ajax 从控制器向 Razor 视图发送值
asp.net利用Ajax和Jquery在前台向后台传参数并返回值