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

Time:03-11

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: Edit TextField selectionStart

※Additional Notes

If using function component, you can use memo to do it, reference: React document.

CodePudding user response:

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>
  );
}

  • Related