1

I'm using React, and want to update array of objects in a state. The overall answer in internet was to use a similar approach to below:

const newState = this.state.elements.slice().concat({key: 'val'});
this.setState({elements: newState});

But the problem I encountered with this issue is that when these data are binded into a render function and components, it re-renders every component.

Example include (map is used from lodash to retrieve index while mapping):

render() {
  return (
    <div>
      {map(this.state.elements, (el, index) => <Component key={`el-${index}`} el={el} />)}
    </div>
  );
}

Even though, the array order doesn't change and the key's of the components doesnt change, everytime the state changes, it re-renders and mounts the component from scratch.

Is there a possible best practice solution to this issue?

Best, Y

Yagiz
  • 1,033
  • 2
  • 21
  • 47
  • You can perfectly use `Array.prototype.map` though. The callback function receives `(currentItem, currentIndex, originalArray)`. – cfraser Dec 12 '17 at 21:38
  • using index as key is an antipattern, check this: https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318 – Juan Martin Gallo Dec 12 '17 at 23:28

1 Answers1

4

Whats happening is that when you call setState the React Virtual Dom diffs state and calls render again. Render calls to a Map function which renders each component. Each component is thrown away and redrawn because the parent component changes.

This is normal and expected behavior by React. It's doing what you're asking of it, you changed state, it redraws the components.

But your question is how do I append to the list of components my new component without redrawing?

I think the issue is that you're relying on the unique key of react to be the index of the array item.

<Component key={`el-${index}`}  

That will forever change every time you update state. What you need to do is use something like name, or string or a generated key or something from the data.

You are using just map function index value and of course after adding new element to the list will trigger a re-render because key value for each of them was changed.

if you did something like this:

<Component key={`el-${item.id}`}  

Where item id is a constant but unique value, like a primary key in a database table. It would not redraw. The key should have a deterministic value.

See React Docs and this other post for more details.