Torch Component in React-Native/Expo
Create a torch component in React-Native/Expo for easy camera flash control.
4th March 2024
Time to read: 1 min
Introduction
Let's walk through the process of creating a simple yet effective torch component in React-Native/Expo. This component allows users to control the flash of their device's camera effortlessly.
Prerequisites
Make sure you have a React-Native/Expo project set up.
To install expo-camera
and @expo/vector-icons
, run the following commands in your terminal:
npm install expo-camera
npm install @expo/vector-icons
Implementation
Let's break down the code step by step:
1. Dependencies
import React, { useState, useEffect, useRef } from "react";
import { View, Pressable, Text } from "react-native";
import { useFocusEffect } from "@react-navigation/native";
import { Camera } from "expo-camera";
import { MaterialIcons } from "@expo/vector-icons";
We import the necessary dependencies, including React, React Native components, and Expo Camera.
2. Component Setup
const Torch = () => {
const [hasPermission, setHasPermission] = useState(null);
const [torchOn, setTorchOn] = useState(false);
const [flashMode, setFlashMode] = useState(0);
const cameraRef = useRef(null);
We set up the state variables and a camera reference using the useRef
hook.
3. Permission Handling
useFocusEffect(
React.useCallback(() => {
const requestCameraPermission = async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === "granted");
};
setTorchOn(false);
requestCameraPermission();
return () => {
Camera.defaultProps.flashMode = Camera.Constants.FlashMode.off;
setHasPermission(null);
setTorchOn(false);
};
}, [])
);
We use the useFocusEffect
hook to request camera permissions when the component is focused and clean up when it is unfocused.
4. Torch Toggle
const handleToggleTorch = () => {
setTorchOn((prevTorchState) => !prevTorchState);
};
We implement a function to toggle the torch state.
5. Torch State Effect
useEffect(() => {
if (cameraRef) {
torchOn
? (Camera.defaultProps.flashMode = Camera.Constants.FlashMode.torch)
: (Camera.defaultProps.flashMode = Camera.Constants.FlashMode.off);
setFlashMode(Camera.defaultProps.flashMode);
}
}, [torchOn]);
useEffect(() => {
if (cameraRef.current) {
cameraRef.current.flashMode = flashMode;
}
}, [flashMode]);
We use two useEffect
hooks to update the flashlight mode based on the torch state.
6. UI Rendering
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Pressable onPress={handleToggleTorch}>
<MaterialIcons
name={torchOn ? "flashlight-on" : "flashlight-off"}
size={120}
color="black"
/>
</Pressable>
<Camera
style={{ position: "absolute", top: 0, left: 0, width: 1, height: 1 }}
ref={cameraRef}
/>
</View>
);
};
export default Torch;
We render the UI, including a toggle button and a hidden camera component.
Conclusion
By following these steps, you've successfully created a versatile torch component in React-Native/Expo for easy camera flash control. To implement this component in your project, create a file named Torch.js and paste the code provided below. Import and use where needed.
Full Code
import React, { useState, useEffect, useRef } from "react";
import { View, Pressable, Text } from "react-native";
import { useFocusEffect } from "@react-navigation/native";
import { Camera } from "expo-camera";
import { MaterialIcons } from "@expo/vector-icons";
const Torch = () => {
const [hasPermission, setHasPermission] = useState(null);
const [torchOn, setTorchOn] = useState(false);
const [flashMode, setFlashMode] = useState(0);
const cameraRef = useRef(null);
useEffect(() => {
if (cameraRef) {
torchOn
? (Camera.defaultProps.flashMode = Camera.Constants.FlashMode.torch)
: (Camera.defaultProps.flashMode = Camera.Constants.FlashMode.off);
setFlashMode(Camera.defaultProps.flashMode);
}
}, [torchOn]);
useEffect(() => {
if (cameraRef.current) {
cameraRef.current.flashMode = flashMode;
}
}, [flashMode]);
useFocusEffect(
React.useCallback(() => {
const requestCameraPermission = async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === "granted");
};
setTorchOn(false);
requestCameraPermission();
return () => {
Camera.defaultProps.flashMode = Camera.Constants.FlashMode.off;
setHasPermission(null);
setTorchOn(false);
};
}, [])
);
const handleToggleTorch = () => {
setTorchOn((prevTorchState) => !prevTorchState);
};
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Pressable onPress={handleToggleTorch}>
<MaterialIcons
name={torchOn ? "flashlight-on" : "flashlight-off"}
size={120}
color="black"
/>
</Pressable>
<Camera
style={{ position: "absolute", top: 0, left: 0, width: 1, height: 1 }}
ref={cameraRef}
/>
</View>
);
};
export default Torch;