what's the right way to remove dynamic DOM Nodes from an event handler in React?

Viewed 1023

DOM manipulation are the simplest stuff offered by a JS library. But in react everything dynamic has to be in the state. It becomes super diificult to just add or remove simple DOM nodes. Maybe this are the cons of React or probably I don't know any other way.

Take a look at this--

class Ripple extends React.Component {
    state = {
        ripples: []
    }

    render() {
        const { className } = this.props;

        return (
            <div onClick={this.rippleNow} className={`${className} material__ripple`}>

            {this.props.children}

            {this.state.ripples.map((Item, index) => (
                <Item key={index} />
            ))}

            </div>
        );
    }

    rippleNow = ({ currentTarget, clientX, clientY }) => {
        const { x, y } = currentTarget.getBoundingClientRect(),
              { offsetHeight, offsetWidth } = currentTarget,
              dia = Math.min(offsetHeight, offsetWidth, 100);


        const styles = {
            top: (clientX - x) - dia / 2,
            left: (clientY - y) - dia / 2,
            width: dia,
            height: dia
        }

        const Wave = () => (
          <div onAnimationEnd={this.removeRipple} style={styles}></div>
        );

        this.setState(prev => {
           ripples: [...prev.ripples, Wave]
       });
    }

    removeRipple = (e) => {
        // How will i remove that element?
        // Or is there any other way to do the same?
    }
 }

How will i remove the element from the state? Or is there any other way to add or remove DOM Elements in react . As react doesn't allow modifying DOM directly .

I am in a real problem . Thanks to those who'll even try to help .

1 Answers

You generally shouldn't be storing elements themselves in the state. Where you are storing <Wave /> in the state, you could much more efficiently store currentTarget, clientX, etc and generate the react element on the render() cycle. From the archived react docs

What shouldn't go in the state? - React components: Build them in render() based on underlying props and state data.

The react material-ui library has a circular material ripple that you can look at if you need some examples of how this is done in practice. Here is the source for their ripple component, and you can see a demo by clicking some of the buttons on this page.

The gist of it is that they only allow a fixed number of ripple elements, and use a ReactTransitionGroup to handle starting and aborting the animations. Each time a ripple is added, the first element of the ripple array is removed and a new item is added.

However, if you don't care about any of that - you can fix your code by just removing the first ripple from the array when you call removeRipple. Since you're always adding the newest ripple to the end of the array, the first one will always be the oldest one.

removeRipple = (e) => {

    // create a new element with the first element removed
    const [, ...shiftedRipples] = this.state.ripples;

    // update the state
    this.setState({ ripples: shiftedRipples });

}
Related