Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactjs lost touchmove after setState

I have a question about Reactjs's touch event.
When the touch moves I will call the setState to render new divs.
But if I keep moving on those new divs the touchmove event won't fire anymore.
Just like the gif below
enter image description here

If I moving out of those divs then it's working.
enter image description here

here's my sample code:

var Container = React.createClass({
    getInitialState: function () {
        return {
            index: 0,
            rows: this.getRowsByIndex(0)
        };
    },

    getRowsByIndex: function(index) {
        var rows = [];

        for (var i = index; i < index + 10; i++) {
            rows.push(i);
        }

        return rows;
    },

    handleTouchStart: function() {
        console.log('start')
    },

    handleTouchMove: function() {
        console.log('move')
        this.setState({
            index: this.state.index + 1,
            rows: this.getRowsByIndex(this.state.index + 1)
        });
    },

    handleTouchEnd: function() {
        console.log('end')
    },

    handleTouchCancel: function() {
        console.log('cancel')
    },

    render: function () {
        return (
            <div style={{ width: 250, height: 300, border: '1px solid' }}
                onTouchStart={this.handleTouchStart}
                onTouchMove={this.handleTouchMove}
                onTouchEnd={this.handleTouchEnd}
                onTouchCancel={this.handleTouchCancel}>
                <div>
                    {this.state.rows.map(function(item, index) {
                        return <div key={item} style={{ width: 100, backgroundColor: '#eee' }}>{item}</div>;
                    })}
                </div>
            </div>
        );
    }
});

For now I only know If I added the pointerEvents: none to the div, then it works. Does anyone have the same problem?

like image 728
Ray Avatar asked Jun 30 '26 16:06

Ray


1 Answers

tl;dr

Change <div key={item} to <div key={index}.

Demo: https://stackblitz.com/edit/react-5yqumb


A bit longer explanation

You need to change this part

{this.state.rows.map(function(item, index) {
    return (
        <div key={item} style={{ width: 100, backgroundColor: '#eee' }}> 
            {item}
        </div>
    );
})}

to (look at key={index}):

{this.state.rows.map(function(item, index) {
    return (
        <div key={index} style={{ width: 100, backgroundColor: '#eee' }}> 
            {item}
        </div>
    );
})}

If you had changed this

<div key={index} style={{ width: 100, backgroundColor: '#eee' }}> 
    {item}
</div>

to another React component like:

class Box extends Component {
  componentDidMount() {
    console.log('mounted <Box />', this.props.children);
  }

  componentWillUnmount() {
    console.log('unmounted <Box />', this.props.children);
  }

  render() {
    return <div style={{ width: 100, backgroundColor: '#eee' }}>{this.props.children}</div>;
  }
}

You could have observed easily that on every state update, you mount and unmount <Box /> components. Look at these console.logs

mounted <Box /> 0
mounted <Box /> 1
mounted <Box /> 2
mounted <Box /> 3
mounted <Box /> 4
mounted <Box /> 5
mounted <Box /> 6
mounted <Box /> 7
mounted <Box /> 8
mounted <Box /> 9
start
unmounted <Box /> 0
mounted <Box /> 10
unmounted <Box /> 1
mounted <Box /> 11
unmounted <Box /> 2
mounted <Box /> 12
unmounted <Box /> 3
mounted <Box /> 13
unmounted <Box /> 4
mounted <Box /> 14
unmounted <Box /> 5
mounted <Box /> 15
unmounted <Box /> 6
mounted <Box /> 16
unmounted <Box /> 7
mounted <Box /> 17
unmounted <Box /> 8
mounted <Box /> 18

Removing and adding dom nodes is the root of the problem. In your case you want to have the same number of <div /> in the DOM and updates just their content so using index in that specific context is safe. You can read more about keys in the official documentation - Lists and Keys - React.

When you change <div key={item} to <div key={index}, console.logs look like this:

mounted <Box /> 0
mounted <Box /> 1
mounted <Box /> 2
mounted <Box /> 3
mounted <Box /> 4
mounted <Box /> 5
mounted <Box /> 6
mounted <Box /> 7
mounted <Box /> 8
mounted <Box /> 9
start
end

You can always try and set breakpoint in the DOM to see that DOM nodes are removed.

with key={index} with key={index}

with key={item} with key={item}

like image 129
Dawid Karabin Avatar answered Jul 03 '26 04:07

Dawid Karabin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!