I can’t see the code where you iterate over the notifications to create Notification
components.
I assume you have a notifications.map(...)
somewhere… To only re-render new components, use the key={...}
attribute inside of the map, with a value unique to each attribute (use index if you don’t have a unique key).
e.g.
<div>
{ notifications.map((notification) => <Notification
key={notification.id}
notification={notification}
/>)
}
</div>
Figured out what was wrong:
I had a <ul></ul>
tag surrounding my <li></li>
tag in my Notification class.
Removed this and all is working as it should.
I have a web app that uses a websocket to receive information from an API I have put together.
Everything works great, however, every time new information arrives from the websocket, the whole list on my frontend (React) is updated.
Here is the relevent code:
componentDidMount(prevState) {
socketIO.on('newNotification', (response) => {
const notifications = this.state.notifications;
console.log(response)
const newNotifications = response.data
this.setState(prevState => ({
notifications: [...this.state.notifications, newNotifications]
}))
});
}
notifications is a list of notifications that is received from my API, which I set to the state.notifications whenever a response is received.
My understanding is React only updates what it needs to, so I’m not sure what is going on.
Here is my Notification component:
import React from "react"
class Notification extends React.Component {
render(){
return(
<ul>
<li
key = {this.props.notification.id}
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>
</ul>
)
}
}
export default Notification
I tried various diferent methods of updating the state, but nothing seems to work.
EDIT: here is the NotificationList class where the Notification component is created:
class NotificationList extends React.Component {
render() {
return(
<ul>
{this.props.notifications.map(notification => (
<Notification
id = {notification.id}
notification = {notification}
handleChangeProps = {this.props.handleChangeProps}
deleteNotificationProps = {this.props.deleteNotificationProps}
/>
))}
</ul>
)
}
}
Thanks @Nick Grealy. I have included the map function in my original post. I have changed this to be “key” instead of “id”, however my whole array is being rerendered still. Maybe I am misinterpretting, but I have a CSS class that is only applied for the first 10 seconds after a notification is created. When a new notification arrives, the whole list is reloaded and the CSS is applied to the whole list
Check your JSX hierarchy. If a parent component is re-rendered, so too, will all it’s children. You can also try wrapping your JSX element in a