Home > Net >  React doesn't rerender component when props change
React doesn't rerender component when props change

Time:04-02

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);
  • Related