Search code examples
javascriptreactjsdom-eventsevent-bubbling

React Event Bubbling: Finding the target Component


I have a <ul> Component wrapping some <li> Components. I want to avoid adding an onClick handler to each li and instead use a single handler on the ul and capture the bubbled events.

What is the correct way of determining / assigning the clicked Component from the bubbled event?

class ListItemComponent extends React.Component {
    public render() {
        return (
            <li>Foo</li>
        )
    }
}

class ListComponent extends React.Component {
    private handleClick(event) {
        const target = event.target;
        // Determine clicked component, or index etc … ?
    }

    public render() {
        const items = this.props.items.map((x, i) => {
            <ListItemComponent active=“false” key={i} />    
        })
        return (
            <ul onClick={this.handleClick} />
                { items }
            </ul>
        )
    }   
}

Solution

  • My solution was to add a data-index attribute to each child which can be used to identify the component.

    This avoids adding multiple event listeners while also avoiding the overhead of multiple ref callbacks to obtain the child DOM elements:

    class ListItemComponent extends React.Component {
        public render() {
            return (
                <li data-index={this.props.index}>Foo</li>
            )
        }
    }
    
    class ListComponent extends React.Component {
        private handleClick(event) {
            const activeIndex = event.target.getAttribute('data-index');
            this.setState({ activeIndex });
        }
    
        public render() {
            const active = this.state.activeIndex;
            const items = this.props.items.map((x, i) => {
                <ListItemComponent active={i === active} key={i} index={i} />    
            })
            return (
                <ul onClick={this.handleClick} />
                    { items }
                </ul>
            )
        }   
    }