ReactJs 上的无限循环渲染组件
Endless loop rendering component on ReactJs
我遇到了无限循环问题,但我看不出是什么触发了它。它似乎在渲染组件时发生。
我有三个组件,组织如下:
TimelineComponent
|--PostComponent
|--UserPopover
TimelineComponenet:
React.createClass({
mixins: [
Reflux.listenTo(TimelineStore, 'onChange'),
],
getInitialState: function() {
return {
posts: [],
}
},
componentWillMount: function(){
Actions.getPostsTimeline();
},
render: function(){
return (
<div className="timeline">
{this.renderPosts()}
</div>
);
},
renderPosts: function (){
return this.state.posts.map(function(post){
return (
<PostComponenet key={post.id} post={post} />
);
});
},
onChange: function(event, posts) {
this.setState({posts: posts});
}
});
PostComponent:
React.createClass({
...
render: function() {
return (
...
<UserPopover userId= {this.props.post.user_id}/>
...
);
}
});
UserPopover:
module.exports = React.createClass({
mixins: [
Reflux.listenTo(UsersStore, 'onChange'),
],
getInitialState: function() {
return {
user: null
};
},
componentWillMount: function(){
Actions.getUser(this.props.userId);
},
render: function() {
return (this.state.user? this.renderContent() : null);
},
renderContent: function(){
console.log(i++);
return (
<div>
<img src={this.state.user.thumbnail} />
<span>{this.state.user.name}</span>
<span>{this.state.user.last_name}</span>
...
</div>
);
},
onChange: function() {
this.setState({
user: UsersStore.findUser(this.props.userId)
});
}
});
最后还有UserStore**:
module.exports = Reflux.createStore({
listenables: [Actions],
users: [],
getUser: function(userId){
return Api.get(url/userId)
.then(function(json){
this.users.push(json);
this.triggerChange();
}.bind(this));
},
findUser: function(userId) {
var user = _.findWhere(this.users, {'id': userId});
if(user){
return user;
}else{
this.getUser(userId);
return [];
}
},
triggerChange: function() {
this.trigger('change', this.users);
}
});
除 UserPopover 组件外,一切正常。
对于每个 PostComponent 正在渲染一个 UserPopOver,它在 willMount 循环中获取数据。
问题是,如果您注意到我在 UserPopover 组件中有这行代码 console.log(i++);
,它会不断递增
...
3820
3821
3822
3823
3824
3825
...
清除一个无限循环,但我真的不知道它来自哪里。如果有人能给我提示,我将不胜感激。
PS:我已经在 UsersStore 中尝试过这种方法,但是所有 PostComponent 都具有相同的 "user":
...
getUser: function(userId){
return Api.get(url/userId)
.then(function(json){
this.user = json;
this.triggerChange();
}.bind(this));
},
triggerChange: function() {
this.trigger('change', this.user);
}
...
并且在 UserPopover
...
onChange: function(event, user) {
this.setState({
user: user
});
}
...
你可以这样做:
TimelineComponent
|--PostComponent
|--UserPopover
UserPopover 只监听变化并自行更新。
UserPopover 监听 store 的变化,它保存哪些用户的数据应该在 popover 中,并在变化时自动更新。您还可以发送要渲染的坐标。无需为每个 Post.
创建 Popover
因为你的帖子是异步获取的,我相信当你的 UserPopover 组件执行它的 componentWillMount 时,props.userId 是未定义的,然后你调用 UsersStore.findUser(this.props.userId ), 在 UserStore 中,调用 getUser 是因为它无法在本地存储中找到用户。
请注意,每次 getUser 的 ajax 完成时,它都会触发。于是UserPopover组件执行onChange函数,再次调用UsersStore.findUser。那是一个无限循环。
请在UserPopover的componentWillMount中添加一个console.log(this.props.userId)看看是不是像我上面说的那样。我其实不是100%确定的。
这是所有UserPopover实例共享同一个UserStore的问题,我认为我们应该重新考虑这些组件和商店的结构。但是我还没有想出最好的办法。
我遇到了无限循环问题,但我看不出是什么触发了它。它似乎在渲染组件时发生。
我有三个组件,组织如下:
TimelineComponent
|--PostComponent
|--UserPopover
TimelineComponenet:
React.createClass({
mixins: [
Reflux.listenTo(TimelineStore, 'onChange'),
],
getInitialState: function() {
return {
posts: [],
}
},
componentWillMount: function(){
Actions.getPostsTimeline();
},
render: function(){
return (
<div className="timeline">
{this.renderPosts()}
</div>
);
},
renderPosts: function (){
return this.state.posts.map(function(post){
return (
<PostComponenet key={post.id} post={post} />
);
});
},
onChange: function(event, posts) {
this.setState({posts: posts});
}
});
PostComponent:
React.createClass({
...
render: function() {
return (
...
<UserPopover userId= {this.props.post.user_id}/>
...
);
}
});
UserPopover:
module.exports = React.createClass({
mixins: [
Reflux.listenTo(UsersStore, 'onChange'),
],
getInitialState: function() {
return {
user: null
};
},
componentWillMount: function(){
Actions.getUser(this.props.userId);
},
render: function() {
return (this.state.user? this.renderContent() : null);
},
renderContent: function(){
console.log(i++);
return (
<div>
<img src={this.state.user.thumbnail} />
<span>{this.state.user.name}</span>
<span>{this.state.user.last_name}</span>
...
</div>
);
},
onChange: function() {
this.setState({
user: UsersStore.findUser(this.props.userId)
});
}
});
最后还有UserStore**:
module.exports = Reflux.createStore({
listenables: [Actions],
users: [],
getUser: function(userId){
return Api.get(url/userId)
.then(function(json){
this.users.push(json);
this.triggerChange();
}.bind(this));
},
findUser: function(userId) {
var user = _.findWhere(this.users, {'id': userId});
if(user){
return user;
}else{
this.getUser(userId);
return [];
}
},
triggerChange: function() {
this.trigger('change', this.users);
}
});
除 UserPopover 组件外,一切正常。
对于每个 PostComponent 正在渲染一个 UserPopOver,它在 willMount 循环中获取数据。
问题是,如果您注意到我在 UserPopover 组件中有这行代码 console.log(i++);
,它会不断递增
...
3820
3821
3822
3823
3824
3825
...
清除一个无限循环,但我真的不知道它来自哪里。如果有人能给我提示,我将不胜感激。
PS:我已经在 UsersStore 中尝试过这种方法,但是所有 PostComponent 都具有相同的 "user":
...
getUser: function(userId){
return Api.get(url/userId)
.then(function(json){
this.user = json;
this.triggerChange();
}.bind(this));
},
triggerChange: function() {
this.trigger('change', this.user);
}
...
并且在 UserPopover
...
onChange: function(event, user) {
this.setState({
user: user
});
}
...
你可以这样做:
TimelineComponent
|--PostComponent
|--UserPopover
UserPopover 只监听变化并自行更新。
UserPopover 监听 store 的变化,它保存哪些用户的数据应该在 popover 中,并在变化时自动更新。您还可以发送要渲染的坐标。无需为每个 Post.
创建 Popover因为你的帖子是异步获取的,我相信当你的 UserPopover 组件执行它的 componentWillMount 时,props.userId 是未定义的,然后你调用 UsersStore.findUser(this.props.userId ), 在 UserStore 中,调用 getUser 是因为它无法在本地存储中找到用户。
请注意,每次 getUser 的 ajax 完成时,它都会触发。于是UserPopover组件执行onChange函数,再次调用UsersStore.findUser。那是一个无限循环。
请在UserPopover的componentWillMount中添加一个console.log(this.props.userId)看看是不是像我上面说的那样。我其实不是100%确定的。
这是所有UserPopover实例共享同一个UserStore的问题,我认为我们应该重新考虑这些组件和商店的结构。但是我还没有想出最好的办法。