1

I'm learning React. Say that I have a ListContainer which renders several ListItems. I want to keep track of the currently selected ListItem, render it in another color, and be able to navigate up and down.

One way would be to store selectedItem as state in ListContainer, and send it down as a prop to ListItem. But if I do it this way, then every time I change selectedItem I will rerender all ListItems because they are dependent on selectedItem. (I should only have to re-render two ListItems, the one that gets deselected, and the one that gets selected).

Is there a way to implement next and previous function without re-rendering all items?

Note: I know that React doesn't re-render unnecessarily in the DOM, but I'm trying to optimize operations on virtual DOM also.

Edit: Here is my example in code. It renders a list, and when the user click one item it gets selected. We also see that "ListItem update" gets printed 100 times, each time we change selection, which happens regardless of PureComponent or React.memo.

let mylist = []
for (let i = 0; i < 100; i++) {
  mylist.push({ text: "node:" + i, id: i })
}

window.mylist = mylist

const ListItem = React.memo (class extends Component {
  componentDidUpdate() {
    console.log('ListItem update')
  }

  render() {
    let backgroundColor = this.props.item.id === this.props.selectedItem ? 'lightgreen' : 'white'
    return (
      <li
        style={{ backgroundColor }}
        onMouseDown={() => this.props.setSelected(this.props.item.id)}
      >
        {this.props.item.text}
      </li>
    )
  }
})

class ListContainer extends Component {
  constructor(props) {
    super(props)
    this.state = {
      selectedItem: 10
    }
    this.setSelected = this.setSelected.bind(this)
  }

  setSelected(id) {
    this.setState({ selectedItem: id })
    this.forceUpdate()
  }

  render() {
    return (
      <ul>
        {this.props.list.map(item =>
          <ListItem
            item={item}
            key={item.id}
            selectedItem={this.state.selectedItem}
            setSelected={this.setSelected}
          />)}
      </ul>
    )
  }
}

function App() {
  return (
    <ListContainer list={mylist} />
  );
}
2
  • 1
    Ti think he expected an example... Commented Dec 6, 2020 at 17:39
  • You can wrap a react memo on the ListItem to prevent rerendering... Commented Dec 6, 2020 at 17:41

1 Answer 1

2

The state you suggesting is the right way to implement it... The other problem with unnecessary renders of the list item can easily be soved by wrapping the export statement like this:

export default React.memo(ListItem) 

This way the only elements that has changed their props will rerender.. be aware that overuse of This can cause memory leaks when using it unnecessarily...

UPDATE

according to your example in addition to the React.memo you can update the way you transfer props to avoid senfing the selected item in each item...

istead of:

let backgroundColor = this.props.item.id === this.props.selectedItem ? 'lightgreen' : 'white'
...
<ListItem
            item={item}
            key={item.id}
            selectedItem={this.state.selectedItem}
            setSelected={this.setSelected}
          />)}

do :

let backgroundColor = this.props.selectedItem ? 'lightgreen' : 'white'
...
<ListItem
            item={item}
            key={item.id}
            selectedItem={item.id === this.state.selectedItem}
            setSelected={this.setSelected}
          />)}

this way the react memo will prevent rerenders when it is possible...

Sign up to request clarification or add additional context in comments.

3 Comments

In this case though, changing selectedItem will change props for all ListItems, and cause them to re-render, even when using React.memo, I think.
It wont cause them to rerender as long as no prop is changing and key property is designed well... try to test it ...
But props are changing, because I need to let ListItem know about selectedItem. I added code to my example (and tried React.memo) to make things more clear.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.