Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: updating one item of the list (setState) instead of all

I have the following code. When changing the value of one element, the entire list is re-render. How can it be avoided by redrawing only one element? I use setState and class components.

import React from "react";
import "./styles.css";

class ListItem extends React.Component {
  
  handleUpdate = () => {
    this.props.onUpdate(this.props.index);
  };

  totalRenders = 0;

  render() {
    
    const { data: { id, value } } = this.props;

    this.totalRenders += 1;
    console.log("Row rendered");

    return (
      <div>
        <strong>id: </strong>{id}: &nbsp;
        <strong>value: </strong>{value} &nbsp;
        <strong>renders count: </strong>{this.totalRenders} &nbsp;
        <button className="button" onClick={this.handleUpdate}> &nbsp;
          Change row value
        </button>
      </div>
    );
  }
}

export default class App extends React.Component {
  state = { list: [{id: 'id 1', value: '11'}, {id: 'id 2', value: '22'}]};

  handleUpdate = (index) => {
    let newState = this.state.list.slice()
    newState[index].value = Math.round(Math.random() + 10);

    this.setState(() => ({
      list: newState
    }));
  };

  render() {
    console.log("App rendered");

    return (
      <div>
        {this.state.list.map((el, index) => (
          <ListItem
            key={el.id}
            data={el}
            index={index}
            onUpdate={this.handleUpdate}
          />
        ))}
      </div>
    );
  }
}

Sandbox: https://codesandbox.io/s/autumn-architecture-ubgh51?file=/src/App.js

like image 925
Schekhovtsov Avatar asked Sep 16 '25 03:09

Schekhovtsov


1 Answers

If you update your app state then that component is supposed to be updated. That the expected behaviour and that's how it should be behave. Now coming to your question. If changes in a row should not make your entire app re-render. Then you should manage your state in your item and any changes in that should be maintained in that to unnecessary re-render.

Here's an example of how to achieve it. You can replace your ListItem with this and check it yourself.

function UpdatedListItem({ data }) {
  const [row, setRow] = React.useState(data);

  React.useEffect(() => setRow(data), [data]);

  const { id, value } = row;
  console.log("Changes in: ", data);

  function handleChange() {
    setRow({
      ...row,
      value: Math.round(100 + Math.random() * 5)
    });
  }

  return (
    <div>
      <strong>id: </strong>
      {id}: &nbsp;
      <strong>value: </strong>
      {value} &nbsp;
      <strong>renders count: </strong>
      {this.renders} &nbsp;
      <button className="button" onClick={handleChange}>
        &nbsp; Change row value
      </button>
    </div>
  );
}

like image 115
Singh3y Avatar answered Sep 19 '25 06:09

Singh3y