3

I have hierarchical, recursive data structure. It's a list of named items and every item can have its own sub-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 unordered list with nested sub-lists. Also I need the ability to mark some items as highlighted and to dehighlight all items. Because of the second requirement information about highlighted items must live in 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 an item highlightedItemsNames changes and every Item re-renders. To display data correctly only the highlighted item and its parents need to re-render. So how can I avoid all of those unnecessary re-renders?

In my application list of items can be a bit big and re-rendering all of it causes app to noticeably freeze on click.

I could implement shouldComponentUpdate in Item that checks if any sub-item should be re-rendered but does this have an actual chance to improve performance over virtual-dom?

I'm not using Redux or any other state management library and I'd rather not do this at this point.

6

1 Answer 1

1

ShouldComponentUpdate is meant for the purpose of check and decide whether re-render is needed or not. It is obviously a wise decision to implement in cases where large items are re-rendering unnecessarily. I guess you should try to implement this event and see the performance. I believe trying is what makes most things perfect.

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

Comments

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.