Hello I'm a beginner in react native, and I'm trying to get the URI of the video picked from Galerie and use it in another component, I'm testing it with console log but this error is appearing
undefined in not an object evaluation props.route.params.source
this is the page that the video will be picked from Galerie:
import React, { useEffect, useState } from 'react'
import { View, Text, TouchableOpacity, Image } from 'react-native'
import { Camera } from 'expo-camera'
import { Audio } from 'expo-av'
import * as ImagePicker from 'expo-image-picker'
import * as MediaLibrary from 'expo-media-library'
import * as VideoThumbnails from 'expo-video-thumbnails';
import { useIsFocused } from '#react-navigation/core'
import { Feather } from '#expo/vector-icons'
import styles from './styles'
import { useNavigation } from '#react-navigation/native'
export default function CameraScreen() {
const [hasCameraPermissions, setHasCameraPermissions] = useState(false)
const [hasAudioPermissions, setHasAudioPermissions] = useState(false)
const [hasGalleryPermissions, setHasGalleryPermissions] = useState(false)
const [cameraRef, setCameraRef] = useState(null)
const [cameraType, setCameraType] = useState(Camera.Constants.Type.back)
const [cameraFlash, setCameraFlash] = useState(Camera.Constants.FlashMode.off)
const [isCameraReady, setIsCameraReady] = useState(false)
const isFocused = useIsFocused()
const navigation = useNavigation()
useEffect(() => {
(async () => {
const cameraStatus = await Camera.requestCameraPermissionsAsync()
setHasCameraPermissions(cameraStatus.status == 'granted')
const audioStatus = await Audio.requestPermissionsAsync()
setHasAudioPermissions(audioStatus.status == 'granted')
const galleryStatus = await ImagePicker.requestMediaLibraryPermissionsAsync()
setHasGalleryPermissions(galleryStatus.status == 'granted')
})()
}, [])
const recordVideo = async () => {
if (cameraRef) {
try {
const options = { maxDuration: 60, quality: Camera.Constants.VideoQuality['480'] }
const videoRecordPromise = cameraRef.recordAsync(options)
if (videoRecordPromise) {
const data = await videoRecordPromise;
const source = data.uri
/*let sourceThumb = await generateThumbnail(source)*/
/*navigation.navigate('savePost', { source, sourceThumb })*/
}
} catch (error) {
console.warn(error)
}
}
}
const stopVideo = async () => {
if (cameraRef) {
cameraRef.stopRecording()
}
}
const pickFromGallery = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Videos,
allowsEditing: true,
aspect: [16, 9],
quality: 1
})
if (!result.cancelled) {
let sourceThumb = await generateThumbnail(result.uri)
navigation.navigate('AddProduct', {source : result.uri})
}
}
if (!hasCameraPermissions || !hasAudioPermissions || !hasGalleryPermissions) {
return (
<View></View>
)
}
return (
<View style={styles.container}>
{isFocused ?
<Camera
ref={ref => setCameraRef(ref)}
style={styles.camera}
ratio={'16:9'}
type={cameraType}
flashMode={cameraFlash}
onCameraReady={() => setIsCameraReady(true)}
/>
: null}
<View style={styles.sideBarContainer}>
<TouchableOpacity
style={styles.sideBarButton}
onPress={() => setCameraType(cameraType === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back)}>
<Feather name="refresh-ccw" size={24} color={'white'} />
<Text style={styles.iconText}>Flip</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.sideBarButton}
onPress={() => setCameraFlash(cameraFlash === Camera.Constants.FlashMode.off ? Camera.Constants.FlashMode.torch : Camera.Constants.FlashMode.off)}>
<Feather name="zap" size={24} color={'white'} />
<Text style={styles.iconText}>Flash</Text>
</TouchableOpacity>
</View>
<View style={styles.bottomBarContainer}>
<View style={{ flex: 1 }}></View>
<View style={styles.recordButtonContainer}>
<TouchableOpacity
disabled={!isCameraReady}
onLongPress={() => recordVideo()}
onPressOut={() => stopVideo()}
style={styles.recordButton}
/>
</View>
<View style={{ flex: 1 }}>
<TouchableOpacity
onPress={() => pickFromGallery()}
style={styles.galleryButton}>
</TouchableOpacity>
</View>
</View>
</View>
)
}
and this is the other page where I want to retrieve the video URI:
import { View, Text } from 'react-native'
import React from 'react'
export default function AddProductScreen(props) {
console.log(props.route.prams.source)
return (
<View>
<Text>AddproductScreen</Text>
</View>
)
}
Maybe is a misspelling? you have console.log(props.route.prams.source) instead of console.log(props.route.params.source)
Related
In a media player application, I try to use "expo-av" library to build a playlist. everything is working fine. But when I press on the backbutton, it is not behaving properly. I tried in many way. but nothing works for me.
I tried while handling backButton, like, sound.unloadAsync(), sound.stopAsync(), setSound(null).
import React, { useEffect, useState } from 'react';
import {
View,
BackHandler,
Text,
TouchableWithoutFeedback,
StyleSheet,
} from 'react-native';
import * as Progress from 'react-native-progress';
import { connect } from 'react-redux';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { Audio } from 'expo-av';
const sectionsAllCards = [
{
id: 'audio-01',
name: 'Body scan: Generic under mindfulness',
link: 'Bodyscan.m4a',
}
];
const MusicPlayerList = ({ navigation, route, ...props }) => {
const [isPlaying, setIsPlaying] = useState(false);
const [progress, setProgress] = useState(0);
const [audioIndex, setAudioIndex] = useState(0);
const [soundObject, setSoundObject] = useState(null);
const audioSources = [
require('../../assests/musics/Bodyscan.m4a')
];
const togglePlayback = async () => {
if (isPlaying) await soundObject.pauseAsync();
else await soundObject.playAsync();
setIsPlaying(!isPlaying);
};
const onPlaybackStatusUpdate = (status) => {
setProgress(status.positionMillis / status.durationMillis);
};
useEffect(() => {
const loadAudio = async () => {
const source = audioSources[audioIndex];
const sound = new Audio.Sound();
try {
await sound.loadAsync(source);
setSoundObject(sound);
sound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
} catch (error) {
console.log(error);
}
};
loadAudio();
}, [audioIndex]);
async function handleBackButtonClick() {
navigation.navigate('LoginSignup');
return true;
}
useEffect(() => {
BackHandler.addEventListener(
'hardwareBackPress',
handleBackButtonClick,
);
return () => {
BackHandler.removeEventListener(
'hardwareBackPress',
handleBackButtonClick,
);
};
}, []);
const handleOnPress = async (index) => {
if (index === audioIndex) togglePlayback();
else {
setIsPlaying(false);
setProgress(0);
await soundObject.stopAsync();
setSoundObject(null);
setAudioIndex(index);
}
};
return (
<View style={{ backgroundColor: '#efefef', flex: 1 }}>
{sectionsAllCards.map((card, index) => (
<TouchableWithoutFeedback
key={card.id}
onPress={() => handleOnPress(index)}
>
<View style={styles.boxContainer}>
<Text style={styles.audioText}>{card.name}</Text>
<View style={styles.audioIconContainer}>
{progress >= 0 && progress <= 1 && (
<View>
<Progress.Circle
style={styles.progress}
progress={audioIndex === index ? progress : 0}
indeterminate={false}
showsText={false}
size={60}
borderWidth={2}
color={'#479162'}
/>
<Text
style={{
position: 'absolute',
left: 11,
top: 10,
}}
>
<MaterialCommunityIcons
name={
isPlaying && audioIndex === index
? 'pause'
: 'play'
}
size={38}
style={{ color: '#479162' }}
/>
</Text>
</View>
)}
</View>
</View>
</TouchableWithoutFeedback>
))}
</View>
);
};
const styles = StyleSheet.create({
boxContainer: {
},
audioText: {
},
});
const mapStateToProps = (state) => ({
accessToken: state.auth.accessToken,
});
export default connect(mapStateToProps, {})(MusicPlayerList);
I'm trying to learning about chat app using expo-react native-typescript. What im doing so far is like below :
ChatRoomScreen.tsx
import React, { useState, useRef, useEffect } from 'react';
import { StyleSheet, Text, View, FlatList, SafeAreaView, ActivityIndicator } from 'react-native'
import { useRoute, useNavigation } from '#react-navigation/core'
import Message from '../components/Message'
import MessageInput from '../components/MessageInput'
// api client
import axios from 'axios';
const ChatRoomScreen = () => {
const route = useRoute()
const mounted = useRef(true);
const roomID = route.params?.id
const user = route.params?.user
const isMe = route.params?.isMe
const [message, setMessage] = useState();
//AxiosRequest
//get chats
const fetchMessages = async () =>{
axios.get('https://mylaravelAPI.com/api/get/'+roomID)
.then(function (response) {
// handle success
const result = response.data.message.reverse();
{setMessage(result)}
})
}
useEffect(() => {
fetchMessages()
},[])
return (
<SafeAreaView style={styles.page}>
<FlatList
data={message}
//Send params to Message
renderItem={({item}) => <Message message={item} roomID={roomID}/> }
inverted
/>
<MessageInput
//Send params to MessageInput
id={route.params?.id}
receiveID={route.params?.user}
userID={route.params?.isMe}
/>
</SafeAreaView>
)
}
export default ChatRoomScreen
Message.tsx
import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
const blue = '#3777f0'
const grey = 'lightgrey'
const myID = '1'
const Message = ({ message, roomID }) => {
const isMe = message.user.id == myID
const roomId = roomID
return (
<View style={[
styles.container, isMe ? styles.rightContainer : styles.leftContainer]}
>
<Text style={{ color: isMe ? 'black' : 'white' }}>{message.content}</Text>
</View>
)
}
export default Message
MessageInput.tsx
import React, { useState, useEffect } from 'react'
import { StyleSheet, Text, View, TextInput, Pressable } from 'react-native'
import { SimpleLineIcons, Feather, MaterialCommunityIcons, AntDesign, Ionicons } from '#expo/vector-icons'
import MessageComponent from "../Message";
// api client
import axios from 'axios';
const MessageInput = ({id, receiveID, userID}) => {
const [message, setMessage] = useState()
const chatroom = id
const senderUserID = userID.id
const receiveUserID = receiveID.id
//Action
//save message
const saveMessage = () => {
axios({
method: 'post',
url: 'https://mylaravelAPI.com/api/post',
headers: {
'content-type': 'application/json',
},
data: JSON.stringify({
"content": message,
"userID": senderUserID,
"replyToID": receiveUserID
})
});
setMessage('')
}
//update message
const updateMessage = () => {
console.log('updateMessage')
}
//OnPress
const onPress2 = () => {
if (chatroom === null) {
{saveMessage()}
}else{
{updateMessage()}
}
}
const onPress = () => {
// console.log(message)
}
return (
<View style={styles.root}>
<View style={styles.inputContainer}>
<SimpleLineIcons name='emotsmile' size={24} color='#595959' style={styles.icon}/>
<TextInput
style={styles.input}
value={message}
onChangeText={setMessage}
placeholder="Signal message..."
/>
<Feather name='camera' size={24} color='#595959' style={styles.icon}/>
<MaterialCommunityIcons name='microphone-outline' size={24} color='#595959' style={styles.icon}/>
</View>
{/* <Pressable onPress={onPress} style={styles.buttonContainer}>
{message ? <Ionicons name="send" size={18} color="white" /> : <AntDesign name='plus' size={24} color='white' />}
</Pressable> */}
<View onPress={onPress} style={styles.buttonContainer}>
{message ?
<Pressable
onPress={onPress2}>
<Ionicons name="send" size={18} color="white" />
</Pressable> :
<Pressable
onPress={onPress}>
<AntDesign name='plus' size={24} color='white' />
</Pressable>
}
</View>
</View>
)
}
export default MessageInput
Everything is working except the message not update or shows ini realtime. It's will show only when i go back to Welcome screen and open the chat/room again... please help me.. thanks
I am using ActivityIndicator for showing the loading screen while my dispatch function dispatches the action and fetches the products from the firebase and renders it on my app screens But this is not happening. My app is showing products that are in store as dummy data and if I refresh the screen then it shows the data from firebase but not the loading spinner to show that loading is true.
ProductOverviewScreen.js:
import React, { useState, useEffect, useCallback } from "react";
import {
FlatList,
View,
Button,
Text,
StyleSheet,
Platform,
ActivityIndicator,
} from "react-native";
import { useSelector, useDispatch } from "react-redux";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import ProductItem from "../../components/shop/ProductItem";
import * as cartActions from "../../store/actions/cart";
import * as productActions from "../../store/actions/products";
import CustomHeaderButton from "../../components/UI/HeaderButton";
import Colors from "../../constants/Colors";
const ProductOverviewScreen = (props) => {
const [IsLoading, setIsLoading] = useState();
const [IsRefreshing, setIsRefreshing] = useState(false);
const [error, setError] = useState();
const products = useSelector((state) => state.products.availableProducts);
const dispatch = useDispatch();
const loadedProducts = useCallback(() => {
setError(null);
setIsRefreshing(true);
dispatch(productActions.fetchProducts())
.then(setIsLoading(false))
.catch((err) => {
setError(err.message);
});
setIsRefreshing(false);
}, [dispatch, setIsLoading, setError]);
useEffect(() => {
const willFocusSub = props.navigation.addListener(
"willFocus",
loadedProducts
);
return () => {
willFocusSub.remove();
};
}, [loadedProducts]);
useEffect(() => {
const loading = async () => {
setIsLoading(true);
await loadedProducts();
setIsLoading(false);
};
}, [dispatch, loadedProducts]);
const selectItemHandler = (id, title) => {
props.navigation.navigate("ProductDetail", {
productId: id,
productTitle: title,
});
};
const addToCartHandler = async (itemData) => {
setIsLoading(true);
await dispatch(cartActions.addToCart(itemData.item));
setIsLoading(false);
};
if (error) {
return (
<View style={styles.loadingSpiner}>
<Text>An Error occurred! </Text>
<Button
title="Try Again"
onPress={loadedProducts}
color={Colors.primary}
/>
</View>
);
}
if (IsLoading) {
return (
<View style={styles.loadingSpiner}>
<ActivityIndicator size="large" color={Colors.primary} />
</View>
);
}
if (!IsLoading && products.length === 0) {
return (
<View style={styles.loadingSpiner}>
<Text>No Product Found!</Text>
</View>
);
}
return (
<FlatList
data={products}
onRefresh={loadedProducts}
refreshing={IsRefreshing}
renderItem={(itemData) => (
<ProductItem
image={itemData.item.imageUrl}
title={itemData.item.title}
price={itemData.item.price}
onSelect={() => {
selectItemHandler(itemData.item.id, itemData.item.title);
}}
>
<Button
color={Colors.primary}
title="View Details"
onPress={() => {
selectItemHandler(itemData.item.id, itemData.item.title);
}}
/>
{IsLoading ? (
<ActivityIndicator size="small" color={Colors.primary} />
) : (
<Button
color={Colors.primary}
title="To Cart"
onPress={() => {
addToCartHandler(itemData);
}}
/>
)}
</ProductItem>
)}
/>
);
};
ProductOverviewScreen.navigationOptions = (navigationData) => {
return {
headerTitle: "All Products",
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Menu"
iconName={Platform.OS === "android" ? "md-menu" : "ios-menu"}
color={Platform.OS === "android" ? Colors.primary : "white"}
onPress={() => {
navigationData.navigation.toggleDrawer();
}}
/>
</HeaderButtons>
),
headerRight: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Cart"
iconName={Platform.OS === "android" ? "md-cart" : "ios-cart"}
onPress={() => {
navigationData.navigation.navigate("Cart");
}}
/>
</HeaderButtons>
),
};
};
const styles = StyleSheet.create({
loadingSpiner: {
flex: 1,
justifyContent: "center",
alignItems: "center",
opacity: 1,
},
});
export default ProductOverviewScreen;
I have also checked on both emulators IOS and android also on my real device. If I open the app on my real device then instantly app renders the data from the firebase but doesn't show a loading spinner.
In useEffect If I try to add dependency loading which costs async code and a function which fetches the data from firebase then it shows an error saying Can't find variable: loading.
Please making loadedProducts from sync to async
I am new to react and am trying to create a basic bar code scanner using this example: https://docs.expo.io/versions/latest/sdk/bar-code-scanner/
import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Button , ViewPropTypes , SafeAreaView, ScrollView} from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
export default function App() {
return (
<View>
<ScrollView style={styles.scrollView}>
<Text style={styles.text}>{"bar code reading goes here"}</Text>
</ScrollView>
{BarCoderScanner()}
</View>
);
}
function bscanner(){
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
return(
<ScrollView style={styles.scrollView}>
<Text style={styles.text}>${data}</Text>
</ScrollView>
);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
{scanned && <Button title={'Tap to Scan Again'} onPress={() => setScanned(false)} />}
</View>
);
}
I am wondering how I can update the main UI, aka App(), from the callback function handleBarCodeScanned.
Create a new state variable: const [data, setData] = useState("");
After you call setScanned(true); call setData(data)
Remove the return code from handleBarCodeScanned
Change this line {scanned && <Button title={'Tap to Scan Again'} onPress={() => setScanned(false)} />} to
{scanned ? (<ScrollView style={styles.scrollView}><Text style={styles.text}>{data}</Text></ScrollView>) : (<Button title={'Tap to Scan Again'} onPress={() => setScanned(false)} />)}
You can create a separate component for the scrollview to cleanup the code in the ternary.
Try this:
import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Button , ViewPropTypes , SafeAreaView, ScrollView} from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
export default function App() {
const [data, setData] = useState('');
return (
<View>
<ScrollView style={styles.scrollView}>
<Text style={styles.text}>{data}</Text>
</ScrollView>
<BScanner onRead={item => setData(item)} />
</View>
);
}
function BScanner({onRead}){
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
onRead(data);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
{scanned && <Button title={'Tap to Scan Again'} onPress={() => setScanned(false)} />}
</View>
);
}
How is styling done after mapping data into a function in react native. The data is displayed correctly but in a raw format. I'd like the data being mapped to be styled into rows with space between each item. I have tried using a flatlist and it throws an error of invariant violation: tried to get frame for out of the range index nan. Kindly help.
import React, {useEffect, useState} from 'react'
import { Text, View, ActivityIndicator, ScrollView, StyleSheet } from 'react-native'
import axios from '../../utils/axios'
//import CurrencyPair from '../../CurrencyPair'
function HomeScreen() {
const [data, setData] = useState([])
const [isLoading, setIsloading] = useState(true)
useEffect(() => {
const interval = setInterval(() => {
const fetchpairs = async() => {
const results = await axios.get('/v3/accounts/{AccountId}/pricing?instruments=AUD_CAD%2CAUD_CHF%2CAUD_JPY%2CAUD_NZD%2CAUD_USD%2CCAD_CHF%2CCAD_JPY%2CCHF_JPY%2CEUR_AUD%2CEUR_CAD%2CEUR_CHF%2CEUR_GBP%2CEUR_NOK%2CEUR_NZD%2CEUR_USD%2CGBP_AUD%2CGBP_CAD%2CGBP_CHF%2CGBP_USD%2CGBP_JPY%2CNZD_CAD%2CNZD_CHF%2CNZD_JPY%2CUSD_CAD%2CUSD_JPY%2CUSD_CHF%2CUSD_ZAR%2CUSD_MXN')
console.log(results.data)
setData(results.data)
setIsloading(false)
}
fetchpairs()
},1000)
}, []);
if(isLoading) {
return (
<ActivityIndicator size="large"/>
)
}
else
return (
<ScrollView
contentContainerStyle={styles.contentContainer}
>
{data.prices && data.prices.map((prices, index) => {
return (
<Text key={index} style={styles.maintext}>
{data.prices[index].instrument}
{data.prices[index].closeoutAsk}
{data.prices[index].closeoutBid}
</Text>
)
})
}
</ScrollView>
)
}
const styles = StyleSheet.create({
contentContainer:{
flex: 1,
marginTop: 20,
justifyContent: "space-around"
}
})
export default HomeScreen
Just use flex to style.
{data.prices && data.prices.map((prices, index) => {
return (
<View
key={index}
style={{
flexDirection: 'row'
//justifyContent:'space-between'
}}>
<Text style={styles.maintext}>{data.prices[index].instrument}</Text>
<Text style={(styles.maintext, { marginLeft: 4 })}>{data.prices[index].closeoutAsk}</Text>
<Text style={(styles.maintext, { marginLeft: 4 })}>{data.prices[index].closeoutBid}</Text>
</View>
)
})
}