ReactJs上的无限循环渲染组件

时间:2015-11-26 02:40:14

标签: javascript reactjs react-router refluxjs

我面临一个无限循环问题,我无法看到触发它的是什么。渲染组件时似乎发生了这种情况。

我有三个组件,组织如下:

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周期中获取数据。

问题是,如果您注意到我在 UserPopover 组件中有这行代码console.log(i++);,则会反复递增

...
3820
3821
3822
3823
3824
3825
...

清除无限循环,但我真的不知道它来自哪里。如果有人能给我一个提示,我将非常感激。

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 个答案:

答案 0 :(得分:2)

因为你的帖子是异步获取,我相信当你的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,我认为我们应该重新考虑这些组件和存储的结构。但我还没有想出最好的方法。

答案 1 :(得分:1)

你可以这样做:

TimelineComponent
   |--PostComponent
   |--UserPopover

UserPopover只是监听更改并自行更新。

UserPopover在商店中侦听更改,该更改包含哪些用户的数据应该在弹出窗口中以及更改更新本身。您也可以发送坐标的位置。无需为每个帖子创建Popover。