Javascript 如何等待AJAX响应并仅在响应之后呈现组件?
我的一个组件有问题。我认为在React呈现Javascript 如何等待AJAX响应并仅在响应之后呈现组件?,javascript,ajax,reactjs,Javascript,Ajax,Reactjs,我的一个组件有问题。我认为在React呈现ChildComp组件之前,AJAX不会从外部服务器加载所有内容 在上面,您可以看到来自服务器的响应树。这是我的组件代码: var ChildComp = React.createClass({ getInitialState: function(){ return { response: [{}] } }, componentWillReceiveProps: function(nextProps){
ChildComp
组件之前,AJAX不会从外部服务器加载所有内容
在上面,您可以看到来自服务器的响应树。这是我的组件代码:
var ChildComp = React.createClass({
getInitialState: function(){
return {
response: [{}]
}
},
componentWillReceiveProps: function(nextProps){
var self = this;
$.ajax({
type: 'GET',
url: '/subscription',
data: {
subscriptionId: nextProps.subscriptionId //1
},
success: function(data){
self.setState({
response: data
});
console.log(data);
}
});
},
render: function(){
var listSubscriptions = this.state.response.map(function(index){
return (
index.id
)
});
return (
<div>
{listSubscriptions}
</div>
)
}
});
id未定义。以及order对象的所有其他属性。为什么是这样?如果我console.log
我在success
函数之后的响应,它会给出所有数据(如图所示)。我的猜测是,当React渲染组件时,只加载第一个对象,然后加载所有其他内部对象。我真的不知道是不是这样(听起来很奇怪),也不知道如何解决这个问题
我也试过类似的东西
success: function(data){
self.setState({
response: data
}, function(){
self.forceUpdate();
})
}.bind(this)
但仍然会在触发my
console.log(数据)
之前进行重新渲染。如何等待AJAX响应并仅在该响应之后呈现组件?首先,您需要将AJAX调用放入componentWillMount()
或componentDidMount()
(如果需要执行一些DOM操作)
componentWillReceiveProps()
is
当组件接收新道具时调用初始渲染时不调用此方法
但是,即使将AJAX调用放在componentWillMount()
或componentDidMount()
中,在AJAX调用完成之前,render()
也可能会被调用为空响应
所以调用的顺序是这样的(我假设您将AJAX调用放在componentWillMount()
中:
componentWillMount()
(AJAX调用被触发)->componentDidMount()
->render()
(以空响应呈现;因此index.order.id
将导致错误)->AJAX调用返回并调用this.setState()
->(其他一些组件生命周期方法,如shouldComponentUpdate()
被调用;有关详细信息,请参见上面的FB链接)->render()
再次被调用
因此,您的问题的解决方案是:
1) 将AJAX调用移动到componentWillMount()
或componentDidMount()
2) 要么将初始状态设置为刚好[]
(与[{}]
相反),要么检查索引中是否为空
var listSubscriptions = this.state.response.map(function(index){
return (
index.id
)
});
下面是您的代码,其中包含一些修改部分的注释
getInitialState: function(){
return {
// [{}] is weird, either use undefined (or [] but undefined is better).
// If you use [], you loose the information of a "pending" request, as
// you won't be able to make a distinction between a pending request,
// and a response that returns an empty array
response: undefined
}
},
render:function(){
//处理响应尚未出现的情况
如果(!this.state.response){
//请注意,如果您不想在dom中放入任何内容,则可以返回false
//这也是您渲染微调器或其他东西的机会。。。
还没到这里就把它还给我!
}
//让您有机会处理ajax请求
//已完成,但结果数组为空
if(this.state.response.length==0){
返回未找到此订阅的结果;
}
//正常情况
var listSubscriptions=this.state.response.map(函数(索引){
返回(
索引id
)
});
返回(
{listSubscriptions}
)
}
我把它扔进了JSBin,似乎无法重现您的问题
每次单击按钮时,它都会将新的道具发送到
,然后触发其组件WillReceiveProps
,发送(假)ajax请求,接收(假)响应,将响应状态设置为(假)响应,并使用显示的正确数据重新呈现组件
我添加的唯一内容是在尝试访问它之前检查index.id==null
,但我认为这并不能解决您无法访问index.order.id
的问题
关于您无法访问index.order.id
的唯一原因是,您可能有一些代码没有显示给我们,它们在某个时候修改了响应
此外,请记住,当React组件的状态或道具发生更改时,它将始终重新渲染,除非您在shouldComponentUpdate
中定义了另一种行为。这意味着,当您从服务器接收整个对象并将其设置为组件中的状态时,它将重新渲染并向您显示更新的状态。没有理由/方式像您在原始帖子中建议的那样“肤浅地呈现”您的响应对象
我不确定这个答案是否有帮助,但希望您可以查看我提供的JSBin,找到一些您可能忽略的内容。只需在componentDidMount()
中执行AJAX调用,在render中您只需检查一下
if(this.state.response === '' || this.state.response === [] || this.state.response === undefined)
return <Loader />
else{
// do your stuff here
}
if(this.state.response==''this.state.response===[]| | this.state.response===未定义)
返回
否则{
//在这里做你的事
}
或者,如果您使用的是react 16.6或更高版本,您可以简单地使用惰性组件。OP在其ajax请求数据中使用收到的道具。这个答案对他不起作用。将Ajax移动到will
或did
mount不会解决问题;在Ajax调用完成之前,几乎肯定还会有一个呈现。为了确保响应数据的格式符合您的要求,您应该向Ajax请求中添加dataType:“json”
。此外,您还可以尝试在shouldComponentUpdate
中记录接收到的新状态。最后,验证index.order
上有哪些属性(如果有)。可能它包含一个字符串而不是属性。我想指出,使用React 16,componentLifecycle已更改,因此其中一些答案可能已过时。我甚至不确定这里的解决代码是什么,但我猜是componentWillMount
函数。AJAX现在是
loadSubscriptionData: function(subscriptionId){
var self = this;
// You probably want to redo the ajax request only when the
// subscriptionId has changed (I guess?)
var subscriptionIdHasChanged =
(this.props.subscriptionId !== subscriptionId)
if ( subscriptionIdHasChanged ) {
// Not required, but can be useful if you want to provide the user
// immediate feedback and erase the existing content before
// the new response has been loaded
this.setState({response: undefined});
$.ajax({
type: 'GET',
url: '/subscription',
data: {
subscriptionId: subscriptionId //1
},
success: function(data){
// Prevent concurrency issues if subscriptionId changes often:
// you are only interested in the results of the last ajax
// request that was made.
if ( self.props.subscriptionId === subscriptionId ) {
self.setState({
response: data
});
}
}
});
}
},
// You want to load subscriptions not only when the component update but also when it gets mounted.
componentDidMount: function(){
this.loadSubscriptionData(this.props.subscriptionId);
},
componentWillReceiveProps: function(nextProps){
this.loadSubscriptionData(nextProps.subscriptionId);
},
render: function(){
// Handle case where the response is not here yet
if ( !this.state.response ) {
// Note that you can return false it you want nothing to be put in the dom
// This is also your chance to render a spinner or something...
return <div>The responsive it not here yet!</div>
}
// Gives you the opportunity to handle the case where the ajax request
// completed but the result array is empty
if ( this.state.response.length === 0 ) {
return <div>No result found for this subscription</div>;
}
// Normal case
var listSubscriptions = this.state.response.map(function(index){
return (
index.id
)
});
return (
<div>
{listSubscriptions}
</div>
)
}
if(this.state.response === '' || this.state.response === [] || this.state.response === undefined)
return <Loader />
else{
// do your stuff here
}