A7DC A7DC -3 years ago 77
React JSX Question

React JS swipe functionality not working as expected

I'm attempting to implement some swiping functionality into my app, but I'm currently struggling to get the correct behaviour I want.

I have a function which is called

onTouchStart
which saves the current touch objects'
clientX
and
clientY
position to the state, like so:

touchStart(e) {
const touchObj = e.touches[0];
this.setState({
startX: touchObj.clientX,
startY: touchObj.clientY,
})
}


After the users begins to move their finger across the screen, I call another function
onTouchMove
, which saves the current
clientX
and
clientY
positions:

touchMove(e) {
const touchObj = e.touches[0];
this.setState({
currentX: touchObj.clientX,
currentY: touchObj.clientY,
})
}


To then figure out whether a swipe was an
up
or
down
swipe, I call another function which takes the start positions and takes away the current positions. I also compare it against a
threshold
of
150
to make sure that it was an actual swipe, and not a long swipe (like a scroll). Here's what that looks like:

touchEnd(e) {
this.setState({
touchStarted: false,
})
if (Math.abs(this.state.startX - this.state.currentX) < this.state.threshold) {
this.setState({
direction: this.state.startY > this.state.currentY ? "top" : "bottom",
})
console.log(this.state.direction);
}
}


The problem



This is detecting
up
and
down
swipes fine, but on the very first swipe a user does, the console.log returns the original state of
none
(as opposed to
up
or
down
).

How do I ensure that the initial swipe is always set to the correct direction?

The problem continues further, whereby the user will have to swipe twice in the opposite direction for the state to be saved to the actual direction which is being swiped, like so:

up // none


up // up


down // up


down // down



Apologies if I've not articulated my problem too well. Here's a link to a CodePen where you can see the problem in further detail (you'll need a phone or an emulator to see the touch events).

Here's also a link to a post which I've been following to get this functionality working.

Any pointers would be highly appreciated. Thanks!

Answer Source

Here is the link to the fixed pen.

touchEnd(e) 
{
    var s = {
      touchStarted: false
    };

    if (Math.abs(this.state.startX - this.state.currentX) < this.state.threshold) 
    {
        s.direction = this.state.startY > this.state.currentY ? "top" : "bottom";
    }

    this.setState(s, () => console.log(this.state.direction))
}

The only "problem" was that you assumed that setState is synchronous and therefore checked state value immediately after its call, whereas it is not. If you want to check value of the state after setState has finished - use its second argument to pass callback function.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download