I have a problem with React components not re-rendering when their props change. GroupLabel takes counter as a prop.
export const GroupLabel = (props) => {
const change = () => {
props.setCurrent(props.group);
let newCounter = props.counter;
newCounter[props.group.ID] = 0;
props.setCounter(newCounter);
};
return (
<li className="person" onClick={change}>
<div className="user">
<img src="..."
</div>
<p className="name-time">
<span className="name">{props.group.name}</span>
</p>
{props.counter[props.group.ID]>0?<span className="badge badge-primary float-right">{props.counter[props.group.ID]}</span>:null}
</li>
);
}
GroupLabel is invoked by its parent component for every group it has in groups (groups is a list of objects and a state).
{groups.length!==0?groups.map(item => {return <GroupLabel counter={counter} setCounter={setCounter} key={item.ID} setCurrent={setCurrent} group={item}/>}):null}
In parent component counter is an object mapping groupID to number of messages this group received via websocket. It is changed like this:
let newCounter = counter; // counter is a current state
newCounter[msgJSON.group] ; // msgJSON.group is id of group to which message is directed
setCounter(newCounter);
And it all works correctly but React still doesn't re-render. From what I read React should re-render its components whenever:
their state changes
their props change
parent component is re-rendered
In this situation both GroupLabel props change and parent state is changing (since counter it passes is his state). I can see in React Dev Tools that counter prop has changed (initially its zero for every group).
I don't give the whole code for the parent component because it is too long.
CodePudding user response:
The problem is that you are mutating state, not creating a new one. When you set state in a function component, react will do a ===
between the old state and the new state. If they're equal, the component does not render.
To fix this, change this:
let newCounter = props.counter;
newCounter[props.group.ID] = 0;
props.setCounter(newCounter);
To this:
let newCounter = {
...props.counter
};
newCounter[props.group.ID] = 0;
props.setCounter(newCounter);
And this:
let newCounter = counter;
newCounter[msgJSON.group] ;
setCounter(newCounter);
To this:
let newCounter = {
...counter;
}
newCounter[msgJSON.group] ;
setCounter(newCounter);