Create a Stop Watch using React Native
Last Updated :
23 Jul, 2025
Stopwatches serve as vital tools for accurately measuring time intervals. By the capabilities of React Native, we can effortlessly develop a versatile stopwatch application compatible with both iOS and Android devices. In this article, we will guide you through the step-by-step process of creating a straightforward stopwatch app using React Native.
To give you a better idea of what we’re going to create, let’s watch a demo video.
Demo Video
Prerequisites:
Step-by-Step Implementation
Step 1: Create a React Native Project
Now, create a project with the following command.
npx create-expo-app app-name --template
Note: Replace the app-name with your app name for example : react-native-demo-app
Next, you might be asked to choose a template. Select one based on your preference as shown in the image below. I am selecting the blank template because it will generate a minimal app that is as clean as an empty canvas in JavaScript.
It completes the project creation and displays a message: "Your Project is ready!" as shown in the image below.
Now go into your project folder, i.e., react-native-demo
cd app-name
Project Structure:
Step 2: Run Application
Start the server by using the following command.
npx expo start
Then, the application will display a QR code.
- For the Android users,
- For the Android Emulator, press "a" as mentioned in the image below.
- For the Physical Device, download the "Expo Go" app from the Play Store. Open the app, and you will see a button labeled "Scan QR Code." Click that button and scan the QR code; it will automatically build the Android app on your device.
- For iOS users, simply scan the QR code using the Camera app.
- If you're using a web browser, it will provide a local host link that you can use as mentioned in the image below.
Step 3: Start Coding
Approach:
In this approach, we create a stopwatch with start, pause, resume, and reset buttons. It utilizes state and refs to manage time and running status, updating time every second through intervals.
Example: The useState hook is utilized for managing the state of both the time (representing current elapsed time) and running variables in the stopwatch. On the other hand, the useRef hook is employed to store references to both the interval and start time, ensuring precise calculations of time. The functions startStopwatch, pauseStopwatch, resetStopwatch, and resumeStopwatch are responsible for handling the behavior of the stopwatch. They effectively manage interval timers, update the elapsed time, and control their running state based on user actions. The UI components in the JSX are rendered by the return statement. It showcases various elements like the header, subheader, current elapsed time, and buttons that change based on the stopwatch's state. To ensure consistent and organized styling, the StyleSheet.create function is used to define styles.
Let's Start!.
- Import libraries: Import required libraries at the top of the file.
JavaScript
// Import necessary hooks and components from React and React Native
import { useState, useRef } from 'react';
import {
View, // Container component for layout
Text, // Component for displaying text
StyleSheet, // For creating styles
TouchableOpacity // For creating touchable buttons
} from 'react-native';
- StyleSheet: Create a StyleSheet to style components like container, header, subHeader, etc.
JavaScript
// Styles for the components
const styles = StyleSheet.create({
container: {
flex: 1, // Take up full screen
justifyContent: 'center', // Center vertically
alignItems: 'center', // Center horizontally
},
header: {
fontSize: 30, // Large font size
color: "green", // Green color
marginBottom: 10, // Space below
},
subHeader: {
fontSize: 18, // Medium font size
marginBottom: 10, // Space below
color: "blue", // Blue color
},
timeText: {
fontSize: 48, // Very large font for time
},
buttonContainer: {
flexDirection: 'row', // Arrange buttons in a row
marginTop: 20, // Space above
},
button: {
paddingVertical: 10, // Vertical padding
paddingHorizontal: 20, // Horizontal padding
borderRadius: 5, // Rounded corners
},
startButton: {
backgroundColor: '#2ecc71', // Green background
marginRight: 10, // Space to the right
},
resetButton: {
backgroundColor: '#e74c3c', // Red background
marginRight: 10, // Space to the right
},
pauseButton: {
backgroundColor: '#f39c12', // Orange background
},
resumeButton: {
backgroundColor: '#3498db', // Blue background
},
buttonText: {
color: 'white', // White text
fontSize: 16, // Medium font size
textAlign: "center",
fontFamily: ""
},
});
Develop UI
- Title & Subtitle: Here is the code to display the title and subtitle of the app using a Text component, which conveys who is providing the app (for ex: "Geeksforgeeks") and its purpose (for ex: "Stop Watch In Native").
JavaScript
{/* App Title */}
<Text style={styles.header}>
Geeksforgeeks
</Text>
{/* Sub-title */}
<Text style={styles.subHeader}>
Stop Watch In Native
</Text>
- Display time: Display time by calling the "time" state variable in Text component and the time will update by calling the setTime useState function.
JavaScript
// State to keep track of elapsed time in seconds
const [time, setTime] = useState(0);
// Below Text component is placed below the Title and Sub-Tile of the app
{/* Display elapsed time */}
<Text style={styles.timeText}>{time}s</Text>
- Buttons: We have four buttons: Start, Reset, Resume, and Pause. Each button does exactly what its name suggests. They are designed using a Text component wrapped in a TouchableOpacity component to make them work as buttons. All the buttons are grouped in a View component.
The Pause button only shows up when the timer is running, which is indicated by a "running" state variable. When "running" is true, only the Pause button is visible. When "running" is false, the Start, Reset, and Resume buttons are shown. Each button triggers a specific method: startStopwatch, resetStopwatch, resumeStopwatch, and pauseStopwatch.
JavaScript
// State to keep track of whether the stopwatch is running
const [running, setRunning] = useState(false);
// Below Code is placed after the Displat time
{/* Button container */}
<View style={styles.buttonContainer}>
{/* If stopwatch is running, show Pause button */}
{running ? (
<TouchableOpacity
style={[styles.button, styles.pauseButton]}
onPress={pauseStopwatch}
>
<Text style={styles.buttonText}>Pause</Text>
</TouchableOpacity>
) : (
// If not running, show Start and Reset buttons
<>
<TouchableOpacity
style={[styles.button, styles.startButton]}
onPress={startStopwatch}
>
<Text style={styles.buttonText}>Start</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.resetButton]}
onPress={resetStopwatch}
>
<Text style={styles.buttonText}>
Reset
</Text>
</TouchableOpacity>
</>
)}
{/* If not running, show Resume button */}
{!running && (
<TouchableOpacity
style={[styles.button, styles.resumeButton]}
onPress={resumeStopwatch}
>
<Text style={styles.buttonText}>Resume</Text>
</TouchableOpacity>
)}
</View>
- Methods: Here we have 4 methods: startStopwatch, resetStopwatch, resumeStopwatch, and pauseStopwatch, providing functionality as their name suggests with the help of intervalRef and startTimeRef useState.
JavaScript
// Ref to store the interval ID for clearing it later
const intervalRef = useRef(null);
// Ref to store the start time (in ms) for accurate time calculation
const startTimeRef = useRef(0);
// All Fnction placed inside the App Component
// Function to start the stopwatch
const startStopwatch = () => {
// Set the start time, accounting for any previously elapsed time
startTimeRef.current = Date.now() - time * 1000;
// Start interval to update time every second
intervalRef.current = setInterval(() => {
// Update time state with elapsed seconds
setTime(Math.floor((Date.now() - startTimeRef.current) / 1000));
}, 1000);
// Set running state to true
setRunning(true);
};
// Function to pause the stopwatch
const pauseStopwatch = () => {
// Clear the interval to stop updating time
clearInterval(intervalRef.current);
// Set running state to false
setRunning(false);
};
// Function to reset the stopwatch
const resetStopwatch = () => {
// Clear the interval
clearInterval(intervalRef.current);
// Reset time to 0
setTime(0);
// Set running state to false
setRunning(false);
};
// Function to resume the stopwatch from paused state
const resumeStopwatch = () => {
// Set the start time to account for already elapsed time
startTimeRef.current = Date.now() - time * 1000;
// Start interval to update time every second
intervalRef.current = setInterval(() => {
// Update time state with elapsed seconds
setTime(Math.floor((Date.now() - startTimeRef.current) / 1000));
}, 1000);
// Set running state to true
setRunning(true);
};
Now, wrap all design code with a View component, return it from the App component, and place all methods and useStates within the App component. Ensure to export the App.
Complete Source Code
App.js:
App.js
// Import necessary hooks and components from React and React Native
import { useState, useRef } from 'react';
import {
View, // Container component for layout
Text, // Component for displaying text
StyleSheet, // For creating styles
TouchableOpacity // For creating touchable buttons
} from 'react-native';
// Main App component
const App = () => {
// State to keep track of elapsed time in seconds
const [time, setTime] = useState(0);
// State to keep track of whether the stopwatch is running
const [running, setRunning] = useState(false);
// Ref to store the interval ID for clearing it later
const intervalRef = useRef(null);
// Ref to store the start time (in ms) for accurate time calculation
const startTimeRef = useRef(0);
// Function to start the stopwatch
const startStopwatch = () => {
// Set the start time, accounting for any previously elapsed time
startTimeRef.current = Date.now() - time * 1000;
// Start interval to update time every second
intervalRef.current = setInterval(() => {
// Update time state with elapsed seconds
setTime(Math.floor((Date.now() - startTimeRef.current) / 1000));
}, 1000);
// Set running state to true
setRunning(true);
};
// Function to pause the stopwatch
const pauseStopwatch = () => {
// Clear the interval to stop updating time
clearInterval(intervalRef.current);
// Set running state to false
setRunning(false);
};
// Function to reset the stopwatch
const resetStopwatch = () => {
// Clear the interval
clearInterval(intervalRef.current);
// Reset time to 0
setTime(0);
// Set running state to false
setRunning(false);
};
// Function to resume the stopwatch from paused state
const resumeStopwatch = () => {
// Set the start time to account for already elapsed time
startTimeRef.current = Date.now() - time * 1000;
// Start interval to update time every second
intervalRef.current = setInterval(() => {
// Update time state with elapsed seconds
setTime(Math.floor((Date.now() - startTimeRef.current) / 1000));
}, 1000);
// Set running state to true
setRunning(true);
};
// Render UI
return (
<View style={styles.container}>
{/* App Title */}
<Text style={styles.header}>
Geeksforgeeks
</Text>
{/* Sub-title */}
<Text style={styles.subHeader}>
Stop Watch In Native
</Text>
{/* Display elapsed time */}
<Text style={styles.timeText}>{time}s</Text>
{/* Button container */}
<View style={styles.buttonContainer}>
{/* If stopwatch is running, show Pause button */}
{running ? (
<TouchableOpacity
style={[styles.button, styles.pauseButton]}
onPress={pauseStopwatch}
>
<Text style={styles.buttonText}>Pause</Text>
</TouchableOpacity>
) : (
// If not running, show Start and Reset buttons
<>
<TouchableOpacity
style={[styles.button, styles.startButton]}
onPress={startStopwatch}
>
<Text style={styles.buttonText}>Start</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.resetButton]}
onPress={resetStopwatch}
>
<Text style={styles.buttonText}>
Reset
</Text>
</TouchableOpacity>
</>
)}
{/* If not running, show Resume button */}
{!running && (
<TouchableOpacity
style={[styles.button, styles.resumeButton]}
onPress={resumeStopwatch}
>
<Text style={styles.buttonText}>Resume</Text>
</TouchableOpacity>
)}
</View>
</View>
);
};
// Styles for the components
const styles = StyleSheet.create({
container: {
flex: 1, // Take up full screen
justifyContent: 'center', // Center vertically
alignItems: 'center', // Center horizontally
},
header: {
fontSize: 30, // Large font size
color: "green", // Green color
marginBottom: 10, // Space below
},
subHeader: {
fontSize: 18, // Medium font size
marginBottom: 10, // Space below
color: "blue", // Blue color
},
timeText: {
fontSize: 48, // Very large font for time
},
buttonContainer: {
flexDirection: 'row', // Arrange buttons in a row
marginTop: 20, // Space above
},
button: {
paddingVertical: 10, // Vertical padding
paddingHorizontal: 20, // Horizontal padding
borderRadius: 5, // Rounded corners
},
startButton: {
backgroundColor: '#2ecc71', // Green background
marginRight: 10, // Space to the right
},
resetButton: {
backgroundColor: '#e74c3c', // Red background
marginRight: 10, // Space to the right
},
pauseButton: {
backgroundColor: '#f39c12', // Orange background
},
resumeButton: {
backgroundColor: '#3498db', // Blue background
},
buttonText: {
color: 'white', // White text
fontSize: 16, // Medium font size
textAlign: "center",
fontFamily: ""
},
});
// Export the App component as default
export default App;
Output: