Search code examples
javascriptreactjsmaterial-components-web

How to use MDCRipple.attachTo on multiple buttons in React Component


I have a simple React component that renders multiple buttons from an array in my props. I'm applying the ripple on DidMount, however, it's only attaching on the first button, the rest are being ignored. It looks like the attachTo only takes the first element. Is there another way to attach to all the buttons on didmount?

class NavBar extends Component {
    constructor(props) {
        super(props);
        this.state = {
            links
        };
    }
    componentDidMount() {
        MDCRipple.attachTo(document.querySelector('.mdc-button'));
    }
    render() {
        return (
            <section>
                {this.state.links.map((link, i) => {
                    return (
                        <StyledLink key={i} to={link.url}>
                            <StyledButton className="mdc-button">
                                <StyledIcon className="material-icons">{link.icon}</StyledIcon>
                                <StyledTypography className="mdc-typography--caption">
                                    {link.title}
                                </StyledTypography>
                            </StyledButton>
                        </StyledLink>
                    );
                })}
            </section>
        );
    }
}

Final markup

<a class="sc-iwsKbI bhaIR">
	<button class="mdc-button sc-dnqmqq ksXmjj mdc-ripple-upgraded" style="--mdc-ripple-fg-size:57.599999999999994px; --mdc-ripple-fg-scale:2.1766951530355496; --mdc-ripple-fg-translate-start:-7.799999999999997px, 19.200000000000003px; --mdc-ripple-fg-translate-end:3.200000000000003px, 19.200000000000003px;">
		...content
	</button>
</a>
<a class="sc-iwsKbI bhaIR">
	<button class="mdc-button sc-dnqmqq ksXmjj">
		...content
	</button>
</a>

Updated I was able to find a way to use the attachTo with each button, but it still seems like there's a better way. I changed by componentDidMount() to:

componentDidMount() {
    this.state.links.forEach((link) => {
        MDCRipple.attachTo(document.getElementById(`button-navbar-${link.id}`));
    });

}

and then changed my render to

<StyledButton id={`button-navbar-${link.id}`} className="mdc-button">

Is there a way to do this without having to iterate through the array?


Solution

  • The react way to do this is to write component that injects the necessary logic.

    class RippleButton extends Component {
        const handleRef = elem => MDCRipple.attachTo(elem);
    
        render() {
            return (
                <StyledButton {...this.props} ref={this.handleRef} />
            );
        }
    }
    

    Then render that component instead of your original StyledButton component and it will call the MDCRipple.attachTo() itself with its ref.

    Depending on how the StyledButton is implemented you may need to use another prop to get the ref to the underlying DOM element. You did not provide enough of your code to exactly know this.