React正在重新渲染我的列表,即使数组中的每个子节点都有其唯一键

时间:2016-12-16 13:54:49

标签: javascript reactjs

因此,据我所知,反应只会用新密钥重新渲染新元素。这不适合我。 我有一个帖子列表,限于3个。 当用户滚动到页面底部时,我添加3到限制,这意味着在页面的底部3应该显示较旧的帖子。 我现在所做的工作,但整个清单正在被重新渲染。它跳到顶部,这也是不想要的(我可以修复,主要问题是重新渲染)。他们都有独特的钥匙。我该如何防止这种行为?

thisGetsCalledWhenANewPostComesIn(newPost){
    let newPosts = _.clone(this.state.posts);
    newPosts.push(newPost);
    newPosts.sort((a,b) => b.time_posted - a.time_posted); 
    this.setState({posts: newPosts});
}

render(){
     return (
         <div ref={ref => {this.timelineRef = ref;}} style={styles.container}>
             {this.state.posts.map(post =>
                 <Post key={post.id} post={post} />
             )}
         </div>
     );
}

3 个答案:

答案 0 :(得分:3)

单独使用唯一键不会阻止重新渲染未更改的组件。除非您为组件扩展PureComponent或实施shouldComponentUpdate,否则React必须render()组件并将其与上一个结果进行比较。

那么,为什么我们需要keys当它真正关于shouldComponentUpdate

为列表中的每个组件提供唯一键的目的是将道具传递给&#34;右键#34;组件实例,以便他们可以正确地比较新旧道具。

想象一下,我们有一个项目列表,例如:

  • A - &gt; componentInstanceA
  • B - &gt; componentInstanceB
  • C - &gt; componentInstanceC

应用过滤器后,必须重新呈现列表以显示新的组件列表,例如:

  • C - &gt; ?

如果没有正确的唯一键,之前呈现A的组件现在将收到C的道具。即使C未更改,组件也必须在收到完全不同的数据时重新呈现:

  • C - &gt; componentInstanceA // OH NO!

使用正确的唯一键,呈现C的组件将再次收到C。然后shouldComponentUpdate将能够认识到render()输出是相同的,并且组件不必重新渲染:

  • C - &gt; componentInstanceC

如果您的商品列表需要很长时间才能呈现,例如如果它是一个长列表或每个元素都是一组复杂的数据,那么您将从防止不必要的重新渲染中受益。

个人轶事

在一个包含100个项目列表的项目中,每个项目生成1000个DOM元素,从

更改
list.map((item, index) => <SomeComp key={index} ... />)

list.map(item => <SomeComp key={item.id} ... />)

将渲染时间缩短了几秒钟。切勿使用数组索引作为键。

答案 1 :(得分:0)

您必须在Post组件中实施shouldComponentUpdate(nextProps, nextState)。考虑扩展Post组件的PureComponent类,而不是默认的React Component

祝你好运!

PS:您可以在渲染方法中使用字符串作为div的ref参数,如下所示:

render() {
  return (
    <div 
      ref='myRef'
      style={styles.container}
    >
      {this.getPostViews()}
    </div>
  );
}

然后,如果您想引用此元素,请像this.refs.myRef一样使用它。无论如何,这只是个人偏好。

答案 2 :(得分:0)

好的,我的坏。我以为我只发布相关的&#34;代码,但事实证明,问题出在我遗漏的代码中:

    this.setState({posts: []}, ()=> {
        this.postListenerRef = completedPostsRef.orderByChild('time')
        .startAt(newProps.filter.fromDate.getTime())
        .endAt(newProps.filter.toDate.getTime())
        .limitToLast(this.props.filter.postCount)
        .on('child_added', snap => {
            Database.fetchPostFromKey(snap.key)
            .then(post => {             
                let newPosts = _.clone(this.state.posts);
                newPosts.push(_.assign(post, {id: snap.key}));
                newPosts.sort((a,b) => b.time_posted - a.time_posted); 
                this.setState({posts: newPosts});
            }).catch(err => {throw err;});
        });
    }); 

我致电setState({posts: []}),我肯定是99%。