how to do i map through this object in React Native? - javascript

it tried using like this
{ options.map( opt => {
return <Text>{opt.value}</Text>
}) }
Here iam taking the data from the backend and iam passing in to the DetailScreen.
class Poll extends Component {
state = {
loading:true,
pollDetails : []
}
componentDidMount(){
fetch('http://192.168.43.22:5000/api/v1/questions/5f1c31e1089847468cb9c508')
.then((response) => response.json())
.then((responseJson) => this.setState({pollDetails:responseJson.data}));
this.setState({loading:false});
}
render() {
const {loading, pollDetails} = this.state;
if(loading){
<View>
<Text><ActivityIndicator/></Text>
</View>
}
return(
<ScrollView>
<DetailsScreen
key={pollDetails._id}
title={pollDetails.title}
options={pollDetails.options}
voteCount={pollDetails.voteCount}
opinionCount={pollDetails.opinionCount}
loaded={true}
votes={60}
/>
</ScrollView>);
}
}
In Here i try to map through the options but it throws the error!
import React, {Component} from 'react';
import {View, Text, StyleSheet, Animated, TouchableOpacity} from 'react-native';
import Card from '../UI/Card';
export default class DetailScreen extends Component{
state = {
width:0,
voteCount: this.props.voteCount
}
handleOnLayout = ( {nativeEvent} ) => {
this.setState({width:nativeEvent.layout.width})
}
handleVotes = (id) => {
console.log(this.state.voteCount)
}
render(){
const {title, voteCount, votes, opinionCount, loaded} = this.props;
const _animatedWidth = new Animated.Value(0);
const animatedAnswerValue = () => {
const percentage = votes / voteCount;
const rowWidth = Math.floor(this.state.width * percentage);
Animated.timing(_animatedWidth,{
toValue:rowWidth,
duration:1500
}).start();
}
animatedAnswerValue();
const getOverlayStyles = (votes) => {
const s = [styles.optionBar];
if(votes > 50){
s.push(styles.optionBarHigh);
}
if(votes < 50 && votes > 20){
s.push(styles.optionBarMedium);
}
if(votes <= 20){
s.push(styles.optionBarLow)
}
return s;
}
return(
<View style={{marginLeft:100}}>
<Text style={{marginTop:50}}>{title}</Text>
{
this.props.options.map((opt,index) => {
return <Text key={index}>{opt.votes}</Text>
})
}
<Text>Just some sample text here!!!</Text>
{/* <TouchableOpacity key={options._id[0]} onPress={() => this.handleVotes(options._id)}>
<Card>
<Text>{options.value}</Text>
<View style={styles.optionBarRow} onLayout={this.handleOnLayout}>
<Animated.View
style={[getOverlayStyles(this.props.votes,loaded), {width:_animatedWidth}]}/>
<View style={styles.opinions}>
<Text style={{textAlign:"center"}}>Opinions</Text>
</View>
</View>
</Card>
</TouchableOpacity> */}
</View>
);
}
}
but it throw error of "Cannot read property 'map' of undefined
ive been scratching my head lately..
i'll be glad if some one sort this out for me!
thanks in advance :)

It might that data haven't been loaded on the very first render.
You can try to add an extra check for option to be in place, like:
{ options && options.map( opt => {
return <Text>{opt.value}</Text>
}) }

Related

Audio is not automatically closing while pressing backbutton in REACT NATIVE application

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 Can't get my exact location using expo-location

THE CODE USING REACT-NATIVE AND EXPO-LOCATION:
import {
View,
Text,
Alert,
SafeAreaView,
RefreshControl,
StyleSheet,
ActivityIndicator,
ScrollView
} from 'react-native';
import React, {
useEffect,
useState
} from 'react';
import * as Location from 'expo-location'
const openWeatherKey = 'cbb62d0f2653b471dbf6ca28aebb813f'
let url = `http://api.openweathermap.org/data/2.5/onecall?&units=metric&exclude=minutely&appid=${openWeatherKey}`
const Weather = () => {
const [forecast, setForecast] = useState(null)
const [refreshing, setRefreshing] = useState(false)
const loadForecast = async () => {
setRefreshing(true)
const {
status
} = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Permission to acces location was denied')
}
let location = await Location.getCurrentPositionAsync({
enableHighAccuracy: true
})
const response = await fetch(`${url}&lat=${location.coords.latitude}&lon=${location.coords.longitude}`)
const data = await response.json()
if (!response.ok) {
Alert.alert('error something went wrong')
} else {
setForecast(data);
}
setRefreshing(false)
}
useEffect(() => {
loadForecast()
}, [])
if (!forecast) {
return (
<SafeAreaView style={styles.loading}>
<ActivityIndicator size='large'/>
</SafeAreaView>
)
}
const current = forecast.current.weather[0]
return (
<SafeAreaView style={styles.container}>
<ScrollView
refreshControl={
<RefreshControl
refreshing={refreshing} onRefresh={() => loadForecast()}/>
}
style={{marginTop:50}}
>
<Text style={styles.title}>
Current Weather
</Text>
<Text style={{alignItems:'center', textAlign:'center'}}>
Your Location
</Text>
<View>
</View>
</ScrollView>
</SafeAreaView>
)
}
export default Weather
)
THE ERROR: 'Error something went wrong'
But i dont understand why he is not able to get the location?
Does somebody know the answer? i think it goes wrong at const response. Also when i use the standard Code for gettting a location from expo-location docs it works?

TypeError: null is not an object (evaluating ''this.state.torchon')

I don't know what am doing wrong in the code below...I want to toggle flash light on/off during camera capturing, but my code is not working, I tried binding the state in different ways but is still not working for me...Below is my code. Please I need help on how to get this working.
import React, { Component } from 'react';
import { View, StyleSheet, Text, TouchableOpacity } from 'react-native';
import { RNCamera } from 'react-native-camera';
import RNFetchBlob from 'rn-fetch-blob';
import Icon from 'react-native-vector-icons/Ionicons';
class cameraComponent extends Component {
toggleTorch()
{
let tstate = this.state.torchon;
if (tstate == RNCamera.Constants.FlashMode.off){
tstate = RNCamera.Constants.FlashMode.torch;
} else {
tstate = RNCamera.Constants.FlashMode.off;
}
this.setState({torchon:tstate})
}
takePicture = async () => {
if(this.camera) {
const options = { quality: 0.5, base64: true };
const data = await this.camera.takePictureAsync(options);
console.log(data.base64)
const path = `${RNFetchBlob.fs.dirs.CacheDir}/test.png`;
console.log('path', path)
try {
RNFetchBlob.fs.writeFile(path, data.base64, 'base64')
}
catch(error) {
console.log(error.message);
}
}
};
render() {
return (
<View style={styles.container}>
<RNCamera
ref = {ref=>{
this.camera=ref;
}}
style={styles.preview}
flashMode={this.state.torchon}
// type = {RNCamera.Constants.Type.back}
>
</RNCamera>
<View style={{ flex: 0, flexDirection: 'row', justifyContent: 'center' }}>
<TouchableOpacity onPress={this.takePicture.bind(this)} style={styles.captureBtn} />
</View>
<TouchableOpacity style={styles.toggleTorch} onPress={this.toggleTorch.bind(this)}>
{ this.state.torchon == RNCamera.Constants.FlashMode.off? (
<Image style={styles.iconbutton} source={require('../images/flashOff.png')} />
) : (
<Image style={styles.iconbutton} source={require('../images/flashOn.png')} />
)
}
</TouchableOpacity>
</View>
);
};
}
export default cameraComponent;
You have not initialized the state anywhere and when you access this.state.torchon it throws the error because this.state is null.
You have to initialize the state.
class cameraComponent extends Component {
this.state={ torchon:RNCamera.Constants.FlashMode.off };
toggleTorch=()=>
{
let tstate = this.state.torchon;
if (tstate == RNCamera.Constants.FlashMode.off){
tstate = RNCamera.Constants.FlashMode.torch;
} else {
tstate = RNCamera.Constants.FlashMode.off;
}
this.setState({torchon:tstate})
}
You can also initialize the state inside the constructor as well.

Conditional rendering with React Hooks : loading

I am learning how to use React Hooks and have been stuck for many hours on something that's supposed to be very simple.
I am trying to display a a text if the state variable "loading" is true. If it's false, I want to display something else.
No matter what I try, "loading" is always false or at least, the UI does not appear to reflect its value.
here is the code:
import React, {useState, useEffect} from 'react';
import {View, SafeAreaView, Text} from 'react-native';
const testScreen= (props) => {
const [loading, setLoading ] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
if(loading)
{
return <Text>Hi</Text>;
}
else
{
return<Text.Hey</Text>
}
}
export default testScreen;
Any help will be more than welcome and I am sorry if this is very basic.
UPDATE: Here is the actual code I am working with. SetLoading is supposed to update the state variable to false but never does or at least, the UI des not render.
import React, {useState, useEffect} from 'react';
import {View, SafeAreaView, Text, ActivityIndicator} from 'react-native';
import CategoryTag from '../Components/CategoryTag';
import firestore from '#react-native-firebase/firestore';
const CategoryScreen = (props) => {
const topicCollection = firestore().collection('Topics')
.where("active","==",true);
//hooks for topics
const [topics,setTopics] = useState([]);
const [loading, setLoading ] = useState(true);
//get all active topics
useEffect(() => {
return topicCollection.onSnapshot(querySnapshot => {
const list = [];
querySnapshot.forEach(doc => {
const { active, name } = doc.data();
list.push({
id: doc.id,
active,
name,
});
});
setTopics(list);
setLoading(false);
});
}, []);
const renderTopics = () =>{
return(
topics.map((item) =>{
return(
<CategoryTag key = {item.id}
color={userTopics.includes(item.name) ?"#51c0cc":"#303239"}
name = {item.name}
isSelected = {userTopics.includes(item.name)}
handleClick = {addTopicToUserTopicCollection}
/>
)
})
)
}
if(loading)
{
return (
<SafeAreaView style={{flex:1, backgroundColor:"#455a65"}}>
<View style={{width:200, padding:20, paddingTop:60}}>
<Text style ={{fontSize:25, fontWeight:"bold",
color:"#fff"}}>What are you</Text>
<Text style ={{fontSize:22, color:"#fff"}}>interested in?
</Text>
</View>
<View style={{flex:1, alignItems:"center",
justifyContent:"center", alignSelf:"center"}}>
<ActivityIndicator />
</View>
</SafeAreaView>
)
}
else // this never runs
{
return (
<SafeAreaView style={{flex:1, backgroundColor:"#455a65"}}>
<View>
<View style={{width:200, padding:20, paddingTop:60}}>
<Text style ={{fontSize:25, fontWeight:"bold",
color:"#fff"}}>What are you</Text>
<Text style ={{fontSize:22, color:"#fff"}}>interested in?
</Text>
</View>
<View style ={{flexDirection:"column", paddingTop:20}}>
<View style ={{padding:15, paddingTop:15,
marginBottom:15,
flexWrap:"wrap", flexDirection:"row"}}>
{renderTopics(topics)}
</View>
</View>
</View>
</SafeAreaView>
);
}
}
export default CategoryScreen;
You are immediately setting your setLoading state to false and therefore loading text might be rendering for fraction of second, or not at all, like a glitch. Try setting setLoading with a timeout and then you will see the intended behaviour.
const TestScreen= (props) => {
const [loading, setLoading ] = useState(true);
useEffect(() => {
setTimeout(()=>setLoading(false), 3000);
}, []);
if(loading)
{
return <Text>Hi</Text>;
}
else
{
return<Text>hey</Text>
}
}

How to Show Activity Indicator Until data if Fetched from Firebase Using Redux

I am Using FireBase as a Database for fetching data in a react-native app using Redux. I want to Show an Activity Indicator until the data is been fetched.
Here is my code Redux :
export function getHome() {
const request = axios({
method: "GET",
url: `${FIREBASEURL}/home.json`
})
.then(response => {
const articles = [];
for (let key in response.data) {
articles.push({
...response.data[key],
id: key
});
}
return articles;
})
.catch(e => {
return false;
});
return {
type: GET_HOME,
payload: request
};
}
Here is my React Native code where data will be shown:
import React, { Component } from "react";
import {
StyleSheet,
View,
Text,
ScrollView,
ActivityIndicator,
TouchableWithoutFeedback,
Image
} from "react-native";
import { connect } from "react-redux";
import { getHome } from "../store/actions/home_actions";
import DemoScreen from "./rn-sound/demo";
class HomeScreen extends Component {
componentDidMount() {
this.props.dispatch(getHome());
}
renderArticle = imgs =>
imgs.articles
? imgs.articles.map((item, i) => (
<TouchableWithoutFeedback
onPress={() => this.props.navigation.navigate(`${item.navigate}`)}
key={i}
>
<View>
<View>
<Image
style={{
height: 220,
width: "100%",
justifyContent: "space-around"
}}
source={{ uri: `${item.image}` }}
resizeMode="cover"
/>
</View>
<View>
<Text >{item.name}</Text>
</View>
<View>
<Text }>{item.tagline}</Text>
</View>
</View>
</TouchableWithoutFeedback>
))
: null;
render() {
return (
<ScrollView}>
{this.renderArticle(this.props.Home)}
</ScrollView>
);
}
}
how to show Activity Indiactor Untill my data from firebase is been Fetched
You can use loading variable in state. You have set false it before fetch command after that set to true. You can see below sample.
constructor(props) {
super(props);
this.state = {
loading: false
};
}
componentDidMount = () => {
this.setState({
loading: true
})
this.props.dispatch(getHome()).then(response=>{
this.setState({
loading: false
})
})
}
render() {
return (
<ScrollView}>
{this.state.loading == false ? (
<View>
{this.renderArticle(this.props.Home)}
</View>
) : (
<ActivityIndicator size="large" />
)}
</ScrollView>
);
}

Categories