You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何仅重新渲染数组中的新元素?

解决React通知列表全量重渲染问题

问题原因分析

当前出现全量重渲染的核心原因有几点:

  1. 列表项未正确设置key:NotificationList中循环渲染Notification组件时,没有给组件本身添加唯一key,React无法精准识别哪些列表项是新增/变更的,导致全量重渲染。
  2. 组件未做渲染优化:Notification组件是普通class组件,默认只要父组件重渲染,不管props是否变化都会跟着重渲染。
  3. 状态更新写法不严谨:setState中直接使用this.state而非传入的prevState,可能导致状态更新异常(虽不是重渲染主因,但需修正)。

分步解决方案

1. 修正状态更新逻辑

在WebSocket回调的setState中,务必使用函数参数提供的prevState来获取最新状态,避免异步更新导致的状态不一致:

componentDidMount() {
    socketIO.on('newNotification', (response) => {
        const newNotification = response.data;
        this.setState(prevState => ({
            // 使用prevState而非this.state确保拿到最新状态
            notifications: [...prevState.notifications, newNotification]
        }));
    });
}

2. 给列表项添加正确的key

在NotificationList的map循环中,将key直接加在Notification组件上(React要求循环的直接子元素必须有唯一key):

class NotificationList extends React.Component {
    render() {
        return(
            <ul>
            {this.props.notifications.map(notification => (
              <Notification 
                key={notification.id} // 新增:给组件添加唯一key
                notification={notification}
                deleteNotificationProps={this.props.deleteNotificationProps}
              />
            ))}
          </ul>
        )
    }
}

3. 优化Notification组件,避免无意义重渲染

将Notification组件改为PureComponent,它会自动对props和state做浅比较,只有当props真正变化时才会重新渲染:

import React from "react";

// 把React.Component改成React.PureComponent
class Notification extends React.PureComponent {
    render(){
        return(
            <li 
                onClick={() => this.props.deleteNotificationProps(this.props.notification.id)}>
                <div className='separator-container'>
                    <div className={'notification-border ' + this.props.notification.stat_abr}>
                        <div className='notification'>
                            <div className='left-notification'>
                                <div className='stat-abr'>{this.props.notification.stat_abr}</div>
                                <div className='game-time'>{this.props.notification.game_time_string}</div>  
                            </div>
                            <div className='middle-notification'>
                                <div className='player-image'>
                                    <img 
                                        src={`http://nhl.bamcontent.com/images/headshots/current/168x168/${this.props.notification.player_id.toString()}.jpg`} 
                                        alt="" 
                                        className="player-img" 
                                    />
                                </div>
                            </div>
                            <div className='right-notification'>{this.props.notification.description}</div>
                        </div>
                    </div>
                </div>
            </li>
        )
    }
}

export default Notification;

注意:移除组件内部的<ul>标签,NotificationList已包含<ul>,嵌套会导致HTML结构错误。

4. 优化回调函数(可选但重要)

如果父组件中的deleteNotificationProps是每次渲染都新建的函数(比如在render里定义的箭头函数),会导致Notification组件的props每次都变化,触发不必要的重渲染。可以在父组件的constructor中绑定函数:

// 父组件示例
class ParentComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { notifications: [] };
        // 绑定函数,确保每次渲染都是同一个引用
        this.deleteNotification = this.deleteNotification.bind(this);
    }

    deleteNotification(notificationId) {
        // 删除逻辑
        this.setState(prevState => ({
            notifications: prevState.notifications.filter(n => n.id !== notificationId)
        }));
    }

    render() {
        return (
            <NotificationList 
                notifications={this.state.notifications}
                deleteNotificationProps={this.deleteNotification}
            />
        );
    }
}

验证效果

完成以上修改后,当WebSocket收到新通知时,React只会渲染新增的Notification组件,原有列表项不会重复渲染。可以在Notification组件的render方法中添加console.log验证,只有新项会打印日志。

内容的提问来源于stack exchange,提问作者dvdrplus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 04:40:27