AsyncStorage not working - reactjs

console.log returns undefined.
AsyncStorage doesn't work. It doesn't save and does not register.
Please help me.
if (this.props.zamqiDetay == 1) {
this.setState({ number0State: this.props.processDetayDeger });
AsyncStorage.setItem('loover', 'sadfasd');
}
Render:
render() {
AsyncStorage.getItem('loover').then((value) => {
this.setState({ loover: value });
}).done();
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<ActivityIndicator />
</View>
);
}
console.log(this.state.loover);
return ();

You can do something like this.
let storage = async () => await AsyncStorage.getItem('item');
storage().then((res)=>{
if(res) {
//we have out data
}
}).catch((err)=>{
// oops
});

You need to declare await keyword while doing setItem and getItem in asynchronous storage
await AsyncStorage.getItem('loover').then((value) => {
this.setState({ loover: value });
}).done();
await AsyncStorage.setItem('loover', 'sadfasd');

Related

Render component from array values in React Native

I'm trying to render component/function from array values.
Main function
const GeneratedHistory = () => {
return (
<View style={styles.container}>
<View style={styles.headerWrapper}>
<Text variant="headlineLarge" style={styles.headersText}>Historia</Text>
<Text variant='labelMedium'>Generowane kody</Text>
</View>
<View style={styles.mainWrapper}>
<ScrollView>
{getItems()}
</ScrollView>
</View>
</View>
I retrieving values from Firestore and saves what i want to array named Items.
function getItems() {
const items = [];
try {
firebase.firestore().collection("Generated").where("username", "==", auth.currentUser.email)
.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
items.push({
qrImage: doc.get("qrImage"),
qrText: doc.get("qrText"),
time: doc.get("time"),
})
});
items.map((item) => {
console.log(item.qrText)
})
});
} catch (error) {
alert('Error occured')
}
}
Nextly i map the array, printing to console and trying to render function named SingleElement.
function singleElement(text) {
return (
{text}
)
}
Logging to console work's fine, but i can't render the function.
Screen just stays white.
So, I have to use async function, in my case, I fetch the data when the window opens and save it to array.
useEffect(() => {
async function fetchData() {
todoRef
.onSnapshot(
querySnaphsot => {
const items = []
querySnaphsot.forEach((doc) => {
const { qrImage, qrText, time } = doc.data()
items.push({
id: doc.id,
qrImage,
qrText,
time,
})
setItems(items);
})
}
)
} fetchData()
}, [])
Then I map the elements and display them in the component.
items.map((item) => {
return <YourComponent key={item.id} text={item.qrText} time={item.time}>
</YourComponent>
})
}

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'currentUser.uid')]

i get this warning when i try to store details to firebase using the currently logged in user.
i followed a online tutorial but i get this problem, is there any alternate method to use to achieve this?
i read about this problem but couldn't find a fix, i saw that its due to the user not being logged in but i did log in
var currentUser
class DecodeScreen extends Component {
addToBorrow = async (booktitle, bookauthor, bookpublisher, bookisbn) => {
currentUser = await firebase.auth().currentUser
var databaseRef = await firebase.database().ref(currentUser.uid).child('BorrowedBooks').push()
databaseRef.set({
'title': booktitle,
'author': bookauthor,
'publisher': bookpublisher,
'isbn': bookisbn
})
}
state = {
data: this.props.navigation.getParam("data", "NO-QR"),
bookData: '',
bookFound: false
}
_isMounted = false
bookSearch = () => {
query = `https://librarydb-19b20.firebaseio.com/books/${9781899606047}.json`,
axios.get(query)
.then((response) => {
const data = response.data ? response.data : false
console.log(data)
if (this._isMounted){
this.setState({ bookData: data, bookFound: true })
}
})
}
renderContent = () => {
if (this.state.bookFound) {
return(
<View style={styles.container2}>
<View style={styles.htext}>
<TextH3>Title :</TextH3>
<TextH4>{this.state.bookData.title}</TextH4>
</View>
<View style={styles.htext}>
<TextH3>Author :</TextH3>
<TextH4>{this.state.bookData.author}</TextH4>
</View>
<View style={styles.htext}>
<TextH3>Publisher :</TextH3>
<TextH4>{this.state.bookData.publisher}</TextH4>
</View>
<View style={styles.htext}>
<TextH3>Isbn :</TextH3>
<TextH4>{this.state.bookData.isbn}</TextH4>
</View>
</View>
)
}
else {
return(
<View style={styles.loading}>
<ActivityIndicator color="blue" size="large" />
</View>
)
}
}
componentDidMount(){
this._isMounted = true
}
componentWillUnmount(){
this._isMounted = false
}
render() {
{this.bookSearch()}
return (
<View style={styles.container}>
{this.renderContent()}
<Button title='Borrow' onPress={() => this.addToBorrow(this.state.bookData.title, this.state.bookData.author, this.state.bookData.publisher, this.state.bookData.isbn)} />
</View>
);
}
}
First, firebase.auth().currentUser is not a promise, and you can't await it. It's either null or a user object.
Second, it's not guaranteed to be populated with a user object on immediate page load. You will need to use an auth state observer to know when the user object first becomes available after a page load.

setState function not assigning boolean.. why?

Im new to react native and i was not able to undestand this behaviour.
in a async function i am setting a loading boolean to the state before an api call.
Now what is strange: after recieving the response i cannot set the loading boolean back to false. it just keeps waiting at the setState function without reaching callback.
I already tryed to setState in multiple calls for every value. or all in one function call. i also tried to assign the whole response to state.
in react native i can console log the response after fetching it form backend. also i am able to assign the response to the state when leaving the loading boolean out (reaching callback).. however not when trying to set the loading boolean back to false.
hint (maybe):
in the json response i include an array. when leaving out the array (not assigning it to state) it behaves like it should...
please help!
// here my mistery
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
}
}
async onLogin() {
try {
this.setState({ loading: true }, function () {
console.log('loading is:' + this.state.loading)
}); //works great
const { name, password } = this.state;
//here the api call
const response =
await fetch(`http://10.0.2.2:3000/api/login/${name}&${password}`);
const answer = await response.json();
if (answer.user == 'OK') {
//now the strange function-call
this.setState({
tickets: answer.tickets, //this is the array..!
title: answer.event.title,
token: answer.token.token,
tokenDa: true,
//loading: false, //only reaching callback when commenting that out
}, function () {
console.log('tickets are :' + this.state.tickets[0].kategorie)
})
// same behaviour here
// this.setState({loading: false}, function(){
// console.log('loading ist ' + this.state.loading);
// });
}
}
catch{
console.log('in CATCH ERROR')
}
}
// here also the render function in case that matters:
render() {
if (this.state.loading) {
return (
<View style={styles.container}>
<ActivityIndicator size='large' />
</View>
);
}
return this.state.tokenDa ? (
<View style={styles.container}>
<Text>Event Title : {this.state.title} </Text>
<Button
title={'scan'}
style={styles.input}
/>
{this.state.tickets.map((ticket, i) => (
<div key={i}>
<Text >TicketKategorie : {ticket.kategorie}</Text>
<Text > Datum und Türöffnung {ticket.gueltig_am}</Text>
<Text >Verkauft {ticket.verkauft}</Text>
<Text >Eingescannt {ticket.abbgebucht}</Text>
</div>
))}
</View>
) : (
<View style={styles.container}>
<TextInput
value={this.state.name}
onChangeText={(name) => this.setState({ name })}
placeholder={'Username'}
style={styles.input}
/>
<TextInput
value={this.state.password}
onChangeText={(password) => this.setState({ password })}
placeholder={'Password'}
secureTextEntry={true}
style={styles.input}
/>
<Button
title={'Login'}
style={styles.input}
onPress={this.onLogin.bind(this)}
/>
</View>
)
};
};
the result is: a loading screen due to a loading attribute which i cannot set back to false. why is this happening!?
You need to wrap the rest of your code inside the callback for the first setState, like this...
this.setState({ loading: true }, async function () {
const { name, password } = this.state;
const response =
await fetch(`http://10.0.2.2:3000/api/login/${name}&${password}`);
const answer = response.json();
if (answer.user == 'OK') {
this.setState({
tickets: answer.tickets, //this is the array..!
title: answer.event.title,
token: answer.token.token,
tokenDa: true,
loading: false
});
}
});
As you may have already deduced, there is an issue with the asynchronous nature of your setStates. To workaround this, we can create another function to handle the the actual API request and use that in the call-back for the first set-state.
setLoading = () => {
this.setState({ loading: true }, () => this.onLogin())
}
onLogin = async () => {
const { name, password } = this.state;
//here the api call
const response = await fetch(`http://10.0.2.2:3000/api/login/${name}&${password}`);
const answer = await response.json();
if (answer.user == 'OK') {
this.setState({
tickets: answer.ticketsm
title: answer.event.title,
token: answer.token.token,
tokenDa: true,
loading: false
}, function () {
console.log('tickets are :' + this.state.tickets[0].kategorie)
})
}

Understanding React Natives setState and componentWillMount from FlatList

So I'm trying to make a simple application with expo and expo audio that will generate a list of audio buttons and text. But I cannot figure out how react works regarding redrawing the setState OUTSIDE componentWillMount and how to remake a soundobject with a new URI
So right now it will work but only playing the FIRST uri, I assume this is because the object still exists.
And it will not change the state of the button, I know this is because react cant see its changing for some reason from FlatList
It works outside of it, if I only make one button in renders view.
FlatList will render the setStates if I use LegacyImplementation=true .. But Im warned this is deprecated. And it renders it for all buttons at the same time
This is my handlerClass:
export class TSSGetter extends React.Component {
constructor(props){
super(props);
this.state ={
isLoading: true,
playingStatus: "Play"
}
}
retrieveData() {
const endpoint = 'http://127.0.0.1:3333/get'
const data = {
"userId": "123412341234",
"hmac": "detteerikkeenrigtighmac"
}
return new Promise((resolve, reject) => {
fetch(endpoint, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'application/json'
},
body: JSON.stringify(data)
})
.then((resp) => {
console.log('hej return')
return resp.json();
})
.then((resp) => {
resolve(resp);
console.log('resp')
}).catch(function(error) {
console.log(error,'naeh')
});
});
}
componentDidMount(){
this.retrieveData()
.then((resp) => {
var pages = resp.books.contentObjects
pages.map((userData) => {
console.log('superduper pages', userData.contentObjectId)
})
this.setState({
isLoading: false,
dataSource: resp.books.contentObjects,
dataroot: resp.books
});
}).catch((err) => {
//handle error
console.log("Api call error2");
alert(err);
})
}
async _playRecording(AudioURL) {
console.log(AudioURL)
const { sound } = await Audio.Sound.createAsync(
{uri: AudioURL},
{
shouldPlay: true,
isLooping: true,
},
this._updateScreenForSoundStatus,
);
this.sound = sound;
this.setState({
playingStatus: 'playing'
});
}
_updateScreenForSoundStatus = (status) => {
if (status.isPlaying && this.state.playingStatus !== "playing") {
this.setState({ playingStatus: "playing" });
} else if (!status.isPlaying && this.state.playingStatus === "playing") {
this.setState({ playingStatus: "donepause" });
}
};
async _pauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
console.log('pausing...');
await this.sound.pauseAsync();
console.log('paused!');
this.setState({
playingStatus: 'donepause',
});
} else {
console.log('playing...');
await this.sound.playAsync();
console.log('playing!');
this.setState({
playingStatus: 'playing',
});
}
}
}
_syncPauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
this.sound.pauseAsync();
} else {
this.sound.playAsync();
}
}
}
_playAndPause = (AudioURL) => {
console.log(AudioURL)
switch (this.state.playingStatus) {
case 'Play':
this._playRecording(AudioURL);
break;
case 'donepause':
case 'playing':
this._pauseAndPlayRecording();
break;
}
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
const styling = {
flex: 1,
paddingTop:10
// flexDirection: 'row'
}
const data = this.state.dataroot;
return(
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) =>
<View>
<TouchableOpacity style={styles.button} onPress={() => this._playAndPause(item.AudioURL)}>
<Text style={styles.buttonText}>
{this.state.playingStatus}+ {item.contentObjectId}
</Text>
</TouchableOpacity>
<Text style={styles.description}>
{item.text},
</Text>
</View>
}
keyExtractor={(item, index) => item.contentObjectId}
/>
</View>
);
}
}
UPDATE: setting extraData={this.state} in flatlist updates the button.. But all the buttons. How do I change the scope of the button?
You could create a specific component for the items in the FlatList. Each of the items will then have their own state.
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { FlatList } from "react-native-gesture-handler";
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => index.toString()}
data={[1, 2, 3, 4, 5]}
renderItem={({ item }) => <Sound />}
/>
</View>
);
}
}
class Sound extends Component {
constructor() {
super();
this.state = {
status: "IDLE"
};
}
onChangeState = value => {
this.setState({
status: value
});
};
render() {
const { status } = this.state;
return (
<View style={{width: 200,paddingVertical: 10}}>
<Text>Status: {status}</Text>
<View style={{ flex: 1,flexDirection: "row", justifyContent: "space-between" }}>
<Text onPress={() => this.onChangeState("PLAYING")}>PLAY</Text>
<Text onPress={() => this.onChangeState("STOPPED")}>STOP</Text>
<Text onPress={() => this.onChangeState("PAUSED")}>PAUSE</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 100,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
I checked out in the docs, here, and I saw that it will re-render just if you pass the state prop, see this explanations:
By passing extraData={this.state} to FlatList we make sure FlatList itself will re-render when the state.selected changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.

Getting "undefined" value for a variable outisde a fetch response in react native ?? Please?

/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, {
Component,
} from 'react';
import {
AppRegistry,
Image,
ListView,
StyleSheet,
Text,
View,
} from 'react-native';
var REQUEST_URL = 'https://api.themoviedb.org/3/movie/popular?api_key=a667a62ffce29c5d1c5211e316ae43f6';
var REQUEST_URL_BASE_IMG = 'https://image.tmdb.org/t/p/w154/'
class Movies extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
var cast = "";
}
componentDidMount() {
this.fetchData(); //1st collection pulled
}
fetchData(){
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.results),
loaded: true,
});
})
.done();
}
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
}
// fetchData2(movie){
// fetch('https://api.themoviedb.org/3/movie/'+movie.id+'/credits?api_key=a667a62ffce29c5d1c5211e316ae43f6')
// .then((response) => response.json())
// .then((responseJson) => {
// cast: responseJson.cast;
// })
// .catch((error) => {
// console.error(error);
// });
// }
renderMovie(movie,arr) {
var arr = [];
// I want the cast variable to be displayed on the screen. It is coming either undefined or prints "s1" which indicates no data.
fetch('https://api.themoviedb.org/3/movie/'+movie.id+'/credits?api_key=a667a62ffce29c5d1c5211e316ae43f6')
.then((response) => response.json())
.then((responseJson) => {
//cast: responseJson.cast;
//test = displaycast(responseJson.cast[0].name);
var cast = responseJson.cast[0].name;
console.log(cast);
})
.catch((error) => {
console.error(error);
});
// fetch('https://api.themoviedb.org/3/movie/'+movie.id+'/credits?api_key=a667a62ffce29c5d1c5211e316ae43f6')
// .then((response) => response.json())
// .then((responseJson) => {
// this.setState({
// cast: responseJson.cast,
// });
// })
// .catch((error) => {
// console.error(error);
// });
return (
<View style={styles.container}>
<Image
source={{uri: 'https://image.tmdb.org/t/p/w92/'+ movie.poster_path.replace(/\//g,"")}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{cast}</Text>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1,
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('Movies', () => Movies);
This is my code. My main concern is that I am getting the response from fetchData inside the renderMovie perfectly and storing it in cast variable. But if I try to access cast variable outside fetch. It shows undefined or empty string.
The entire point of not having this fetch with earlier is because I want to use the fetch response of 1st fetch Operation to get move.id and use it in the 2nd fetch request to get more details.
That's happening because JavaScript is asynchronous. I'd recommend doing something like your other fetch and set a loading state to know when you've fetched the cast and use that to render.

Resources