Компонент рендеринга бесконечного цикла на 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)
});
}
});
наконец, есть также UsersStore**:
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.
дело в том, если вы заметили, что у меня есть эта строка кода console.log(i++);
на UserPopover компонент, который увеличивается снова и снова
...
3820
3821
3822
3823
3824
3825
...
Clearl бесконечный цикл, но я действительно не знаю, откуда он берется. Если бы кто-нибудь мог дать мне подсказка я буду очень благодарен.
PS: я уже пробовал этот подход в UsersStore но тогда все PostComponent у того же "пользователя":
...
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
});
}
...
2 ответов
поскольку ваши сообщения являются fetch async, я считаю, что при выполнении компонента UserPopover это componentWillMount, реквизит.userId не определен, а затем вы вызываете UsersStore.findUser(это.реквизит.userId), в UserStore getUser вызывается, потому что он не может найти пользователя в локальном хранилище.
обратите внимание, что каждый раз, когда ajax getUser закончил, он срабатывает. Поэтому компонент UserPopover выполнять функцию onChange и вызов UsersStore.снова findUser. Это бесконечная петля.
пожалуйста, добавьте консоль.журнал(это.реквизит.userId) в компоненте UserPopover, чтобы узнать, похоже ли это на то, что я сказал выше. Я на самом деле не уверен на 100%.
это проблема, что все экземпляры UserPopover имеют один и тот же UserStore, я думаю, мы должны переосмыслить структуру этих компонентов и магазинов. Но я еще не придумал лучшего способа.
вы можете сделать это так:
TimelineComponent
|--PostComponent
|--UserPopover
UserPopover просто слушайте изменения и обновляйте себя.
UserPopover прослушивает изменения в магазине, который содержит данные пользователя, которые должны быть в popover и при обновлении изменений. Вы также можете отправить координаты, где визуализировать. Нет необходимости создавать Popover для каждого сообщения.