Reputation: 3
It does not wait to display When I get data from AsyncStorage
It returns value before catches the value.
I cannot use Async Await on functions. If so it does not compile.
I have searched around the whole day today but I could not find the answer.
How can I solve this simple problem, but complex to me?
React code
import React from 'react';
import { StyleSheet, View, Text, AsyncStorage, TouchableOpacity } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import { getUsername } from '../actions';
export default HomeScreen = ({ navigation }) => {
DisplayUsername = () => {
var info = useSelector(state => state.login_info_reducer);
if (Object.entries(info).length === 0 && info.constructor === Object) {
AsyncStorage.getItem('username').then(name => {
info.username = name;
return info;
});
}
else {
return info;
}
}
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => { navigation.navigate('Friends') }}>
<Text>Welcome {DisplayUsername()}</Text>
<Text>Click Here</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
});
Upvotes: 0
Views: 4484
Reputation: 2652
(Disclaimer -- I'm familiar with the web version of React but I'm guessing that these patterns are similar if not identical in react-native.)
You're trying to do something asynchronous (DisplayUsername
) during a synchronous operation (render
). React does not permit render to be asynchronous; your render function always needs to return something that React understands (either UI elements or an empty value such as null
or an empty array).
That means your component has two states: one state where it doesn't yet know what the username is, and one state where it has finished using AsyncStorage
, and it does know the user name. That's a hint that you can use react state
to hold the user name data.
The 'standard' way to fetch external data in React is to do it in a component's componentDidUpdate
method (which is fired after the component has first rendered) or the useEffect
hook with functional components (which is fired after every render). So this is what you want to implement:
AsyncStorage
, asynchronouslyHere's some psuedocode for implementing those steps with a functional component:
export default HomeScreen = ({ navigation }) => {
// set up state and setter for username state
const [username, setUsername] = useState('');
// effect hook for fetching username
useEffect(() => {
doSomethingToGetUsername().then(result => {
setUsername(result);
}).catch(error => {
console.log(error);
});
}, [username]);
const usernameTxt = ` ${username}` || '';
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => { navigation.navigate('Friends') }}>
<Text>Welcome{usernameTxt}</Text>
<Text>Click Here</Text>
</TouchableOpacity>
</View>
)
}
Upvotes: 1