Skip to content

Edvins Antonovs

Creating a swipeable stories component in React

I'm excited to walk you through the development of a simple yet effective stories component using React. This component mimics the functionality of story-based content familiar from social media platforms, offering an engaging way to present a sequence of stories. Swiping is implemented using touch events, making the experience smooth and intuitive, especially on mobile devices. For desktop users, the component also supports mouse-based navigation.


Overview

The Stories component leverages React hooks and touch event listeners to create a smooth navigation experience. We'll be using useState, useEffect, and useRef to manage state and side effects, and to reference DOM elements.

Stories.tsx
1import React, { useState, useEffect, useRef } from 'react';
2
3const Stories = () => {
4 const [currentStoryIndex, setCurrentStoryIndex] = useState<number>(0);
5 const intervalRef = useRef<ReturnType<typeof setInterval>>();
6
7 const goToPrevStory = () => {
8 // Logic to navigate to the previous story
9 setCurrentStoryIndex(prevIndex => Math.max(prevIndex - 1, 0));
10 };
11
12 const goToNextStory = () => {
13 // Logic to navigate to the next story
14 setCurrentStoryIndex(prevIndex => prevIndex + 1);
15 };
16
17 useEffect(() => {
18 const container = document.getElementById('stories-container');
19
20 if (container) {
21 let touchStartX: number | null = null;
22
23 const handleTouchStart: EventListener = (e) => {
24 const touchEvent = e as TouchEvent;
25 touchStartX = touchEvent.touches[0].clientX;
26 };
27
28 const handleTouchEnd: EventListener = (e) => {
29 if (touchStartX === null) {
30 return;
31 }
32
33 const touchEndX = (e as TouchEvent).changedTouches[0].clientX;
34 const deltaX = touchEndX - touchStartX;
35
36 if (deltaX > 50) {
37 goToPrevStory();
38 } else if (deltaX < -50) {
39 goToNextStory();
40 }
41
42 touchStartX = null;
43 };
44
45 container.addEventListener('touchstart', handleTouchStart);
46 container.addEventListener('touchend', handleTouchEnd);
47
48 return () => {
49 container?.removeEventListener('touchstart', handleTouchStart);
50 container?.removeEventListener('touchend', handleTouchEnd);
51 };
52 }
53 }, [goToPrevStory, goToNextStory]);
54
55 return (
56 <div id="stories-container">
57 {/* Content of stories container */}
58 </div>
59 );
60};
61
62export default Stories;

Explanation

State Management

  • currentStoryIndex: Keeps track of the current story being displayed.
  • intervalRef: Utilised for managing intervals if you plan to auto-progress stories.

Navigation Functions

  • goToPrevStory: Decrements the currentStoryIndex, ensuring it doesn't go below zero.
  • goToNextStory: Increments the currentStoryIndex.

Touch Event Handling

  • useEffect: Adds touch event listeners to enable swipe navigation. On unmount, it cleans up these listeners.
  • handleTouchStart: Captures the initial touch position.
  • handleTouchEnd: Determines the swipe direction by comparing the end position with the start position, then navigates accordingly.
    • If deltaX (difference between touchEndX and touchStartX) is greater than 50, it indicates a swipe to the right, triggering goToPrevStory.
    • If deltaX is less than -50, it indicates a swipe to the left, triggering goToNextStory.

Next steps

Okay, now you have the basic structure of the Stories component with swipe navigation implemented. Now it's up to you to add the actual story content and styling to make it visually appealing. You can also extend the component with additional features like auto-progression, indicators, or custom animations. The possibilities are endless!

What I did for my project was to add an auto-play/auto-progression through the stories, by impleneneting a setInterval that calls goToNextStory every few seconds. This way, the stories automatically advance without user interaction. Story content can be dynamically rendered based on the currentStoryIndex, allowing you to display different content for each story. Indicators can be added to show the current story index, giving users a visual cue of their progress.

© 2024 by Edvins Antonovs. All rights reserved.