How to avoid re-rendering in nested lists in React

I have a hierarchical recursive data structure. It is a list of named items, and each item can have its own list of items. It looks like this:

const items = [
    {
        name: 'item1',
        items: [
            {name: 'item2'},
            {name: 'item3'},
            {name: 'item4', items: [
                {
                    name: 'item5'
                }
            ]},
        ]
    },
    {
        name: 'item6'
    }
]

      

I want to display it in an unordered list with nested signatures. I also need to be able to mark some items as selected and highlight all items. Due to the second requirement, information about the selected items must be in the top-level component.

My naive implementation looks like this:

class App extends Component {
    constructor() {
        super(...arguments)
        this.state = {
            items: items,
            highlightedItemsNames: {},
        }
        this.handleHighligtItem = (item) => {
            this.setState({highlightedItemsNames: {
                ...this.state.highlightedItemsNames, [item.name]: true
            }})
        }
        this.handleDehighlightAllItems = () => {
            this.setState({highlightedItemsNames: {}})
        }
    }

    render() {
        return <div>
            <button onClick={this.handleDehighlightAllItems}>dehighlight</button>
            <List
                items={this.state.items}
                highlightedItemsNames={this.state.highlightedItemsNames}
                onHighlight={this.handleHighligtItem}
            />
        </div>
    }
}


function List(props) {
    return <ul>
        {props.items.map(item => <li key={item.name}>
            <Item
                item={item}
                highlighted={props.highlightedItemsNames[item.name]}
                highlightedItemsNames={props.highlightedItemsNames}
                onHighlight={props.onHighlight}
            />
        </li>)}
    </ul>
}


function Item(props) {
    let className = "item"
    if (props.highlighted) {
        className += '-highlighted'
    }
    console.log('renders item', props.item.name)
    return <div>
        <span className={className}>{props.item.name}</span>
        <button onClick={() => props.onHighlight(props.item)}>highlight</button>
        {props.item.items ? <List
            items={props.item.items}
            highlightedItemsNames={props.highlightedItemsNames}
            onHighlight={props.onHighlight}
        /> : null}
    </div>
}

      

But now when I highlight the highlightedItemsNames

change item and each one Item

re-renders. To display the data correctly, you only need to redisplay the selected item and its parents. So how can I avoid all unnecessary re-renders?

In my application, the list of items can be a bit large, and re-rendering all causes the application to noticeably freeze the click.

I could implement shouldComponentUpdate

in Item

that checks if any subitem should be redrawn, but does this have a real chance of improving performance over virtual dom?

I am not using Redux or any other government control library, and I would rather not do that for now.

+3


source to share


1 answer


ShouldComponentUpdate

designed to check and decide whether or not re-processing is necessary. It is, of course, a smart decision to implement in cases where large items are re-processed unnecessarily. I think you should try to implement this event and see the performance. I believe that trying is what makes most things perfect.



+1


source







All Articles