Counter with Async Storage in React Native - react-native

I am new to React Native.
I want to make a counter using Async storage in React Native Expo.
Async storage works with string value but I need to use integer value and can't find an example to create it.
I would appreciate it if you suggest with SQLite or if there is a different storage area.
storeData = async (counter) => {
try {
await AsyncStorage.setItem('', counter)
} catch (e) {
}
}
getData = async () => {
try {
const value = await AsyncStorage.getItem('counter')
if(counter !== null) {
}
} catch(e) {
}
}
render() {
return(
<SafeAreaView style={styles.container}>
<ImageBackground style={styles.image}>
<View style={{marginBottom: 250}}>
<Text style={styles.counter}>{counter}</Text>
</View>
<TouchableOpacity
style={styles.floatingButton1}
onPress={this.onAddCounter}>
<Text style={{fontSize:13, color:"white", fontWeight:"600"}}>Tap to Counter</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.resetButton1}
onPress={this.onReset1}>
<Icon name="undo" size={20} color="#900"/>
</TouchableOpacity>
</ImageBackground>
</SafeAreaView>
);
}
}

You can convert the integer to a string when you store the value:
number.toString()
And convert it to integer when you retrieve the value
parseInt(string)
Basically it will become
storeData = async (counter) => {
try {
await AsyncStorage.setItem('counter', counter.toString())
} catch (e) {
}
}
getData = async () => {
try {
const value = await AsyncStorage.getItem('counter')
if(counter !== null) {
value = parseInt(value)
}
} catch(e) {
}
}

Use JSON.parse for values getting from AsyncStorage
https://react-native-async-storage.github.io/async-storage/docs/usage/#reading-object-value

Related

Is it possible to render/return React Native elements from functions?

so i want to load some data from my server using axios in React native. The data was retrieved successfully, but i don't know how to display it on the page. When i click button 'Load students' it does axios get method and after that calls method 'showStudents' but that method doesn't return anything. I really don't understand how rendering works in react native so i would appreciate any help and guidance. Also if there is easier way to do all of this, i'm open for suggestions.
export default function Students() {
const [s, setStudents] = useState('')
const getStudents = async () => {
try{
const {data: {students}} = await axios.get('http://192.168.1.2:3000/api/v1/students')
setStudents(students)
//console.log(students)
showStudents()
}
catch(error){
console.log(error)
}
}
const showStudents = () => {
return( <ScrollView>
{
s.map((student) => (
<ListItem key={student._id} bottomDivider>
<ListItem.Content>
<ListItem.Title>{student.firstName}</ListItem.Title>
<ListItem.Subtitle>{student.index}</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>)
}
return (
<View style={styles.container}>
<Button title='Load students' color='green' onPress={getStudents}/>
</View>
);
}
The function showStudents returns a JSX component, but not inside of the render function of the component Students.
You can just create a new JSX component and use conditional rendering in order to render it whenever the state s (I would call it students) is not undefined and has a length strictly greater than zero.
const [students, setStudents] = useState()
const getStudents = async () => {
try{
const {data: {students}} = await axios.get('http://192.168.1.2:3000/api/v1/students')
setStudents(students)
}
catch(error){
console.log(error)
}
}
return (
<View style={styles.container}>
<Button title='Load students' color='green' onPress={getStudents}/>
{
students && students.length > 0 ? <ScrollView>
{
students.map((student) => (
<ListItem key={student._id} bottomDivider>
<ListItem.Content>
<ListItem.Title>{student.firstName}</ListItem.Title>
<ListItem.Subtitle>{student.index}</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView> : null
}
</View>
);
We could create a new component to make things more structured. Let us introduce StudentList.
export function StudentList({students}) {
return <ScrollView>
{
students.map((student) => (
<ListItem key={student._id} bottomDivider>
<ListItem.Content>
<ListItem.Title>{student.firstName}</ListItem.Title>
<ListItem.Subtitle>{student.index}</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>
}
Then, reuse this new component.
const [students, setStudents] = useState()
const getStudents = async () => {
try{
const {data: {students}} = await axios.get('http://192.168.1.2:3000/api/v1/students')
setStudents(students)
}
catch(error){
console.log(error)
}
}
return (
<View style={styles.container}>
<Button title='Load students' color='green' onPress={getStudents}/>
{
students && students.length > 0 ? <StudentList students={students} /> : null
}
</View>
);

How to use asyncStorage inside useEffect

I'm building a mobile game using react native and I'm trying to retrieve the best value storage on it to display on the screen. The problem is that it seems that react native is rendering the screen before it retrieves the value and then it doesn't re-render when the value is updated using setBest(), so no value is displayed.
Here is the code:
const navigation = useNavigation()
const [result, setResult] = useState('')
const [best, setBest] = useState('')
useEffect(() => {
const Storage = async (key,value) => {
await AsyncStorage.setItem(key,value)
}
const Retrieve = async (key) => {
const value = await AsyncStorage.getItem(key)
setBest(()=>value)
}
Retrieve('1').catch(console.error)
setResult(route.params.paramKey)
if(route.params.paramKey>best){
var aux = result.toString()
Storage('1',aux)
console.log(best)
}
}, [])
return (
<View style={styles.container}>
<View style={styles.textView}>
<Text style={styles.tituloText}>Melhor pontuação</Text>
<Text style={styles.tituloText}>{best}</Text>
<Text style={styles.tituloText}>Sua pontuação</Text>
<Text style={styles.resultText}>{result}</Text>
<View style={styles.viewBtn}>
<TouchableOpacity style={styles.viewBack} onPress={() => navigation.navigate('Modo1')}>
<Icon style={styles.iconBack} name="backward" />
</TouchableOpacity>
<TouchableOpacity style={styles.viewHome} onPress={() => navigation.dispatch(StackActions.popToTop)}>
<Icon style={styles.iconBack} name="home" />
</TouchableOpacity>
</View>
</View>
</View>
);
}
Thanks for the help guys! I've been struggling with this for days and any help will be appreciated!
This is how you retrieve the value..
useEffect(() => {
AsyncStorage.getItem('key').then(value => {
if (value != null) {
console.log(value);
setBest(value);
}
});
}, []);
also don't forget to add the import statement..
To set the value you must use
AsyncStorage.setItem('key', value);
You can use Async Functions inside of ~useEffect()` like this:
useEffect(() => {
(async () => {
async function getData() {
try {
const value = await AsyncStorage.getItem('myKey');
if (value !== null) {
setData(value);
}
} catch (error) {
console.log(error);
}
}
getData();
})();
}, []);
}

how to transfer RecyclerListView from class component to functional

I faced RecyclerListView for the first time in legacy code, so I needed to rewrite that in functiona style, but when React tries to return RecyclerListView, programm freezes and do not even enter renderBetItem function, console.log doesn`t even appear. Here is the code parts
let dataProvider = new DataProvider((r1, r2) => {
return true;
});
let layoutProvider = new LayoutProvider(
() => 0,
(type, dim) => {
dim.width = width;
dim.height = 110;
}
);
componentDidMount() {
this.setState({isLoading: true});
this.props.footballEvents && this.initialManipulations(this.props.footballEvents);
this.setState({isLoading: false});
}
initialManipulations = (events) => {
if (events.length) {
const newEventArr = events.map((event) => eventManipulations(event, 'fromFootball'));
this.setState({liveEvents: this.dataProvider.cloneWithRows(newEventArr), loading: false});
}
}
const renderBetItem = (type, data) => {
console.log('entered renderBetItem')
return (
<View><Text>Hello</Text></View>
)
}
return (
<View style={{backgroundColor: whiteLabel.mainBackground, flex: 1}}>
{isLoading === false ?
<RecyclerListView
rowRenderer={renderBetItem}
key={keyForLive}
dataProvider={liveEvents}
layoutProvider={layoutProvider}
/>
:
<ActivityIndicator
color={whiteLabel.homeTabColorActive}
size='large'
style={{marginTop: '20%'}}
/>
}
</View>
)
Do you have any idea what`s wrong with this code?

How to Control async method react-native

I want to send data to another component. I get datas from
AsyncStorage.getItem('myKey');
But when start async, component start to render so it sends null data to another component.
here is my methods ;
componentWillMount(){
this.getdata();
}
getdata = async () => {
console.log("console1");
const value = await AsyncStorage.getItem('myKey');
console.log("console2");
let valuePrsed = JSON.parse(value);
if(valuePrsed.username != null && valuePrsed.password != null)
{
this.setState({values: valuePrsed});
}
}
and this is my render method ;
render() {
console.log("rende splashscreen: ", this.state.values);
let { fadeAnim } = this.state;
return (
<View style = {{flex:1}}>
<LoginForm profile = {this.state.values}/>
<Animated.View style={{ ...this.props.style, opacity: fadeAnim }} >
{this.props.children}
<ImageBackground style={styles.logo1} source={require('../../image/dataLogo.jpeg')} >
</ImageBackground>
</Animated.View>
</View>
);
}
I send datas to LoginForm. I want to ask one more question. If I use <LoginForm /> like this, it ruins my component. How can I send with different way ?
Only render if it's ready to render. the way I do it is initialize a state lets say isReady and set to false then set it to true when you have the value.
Would look like this:
export default class test extends Component {
constructor(props) {
super(props)
this.state = {
isReady:false
}
}
componentWillMount(){
this.getdata();
}
getdata = async () => {
const value = await AsyncStorage.getItem('myKey');
this.setState({isReady:true})
let valuePrsed = JSON.parse(value);
if(valuePrsed.username != null && valuePrsed.password != null)
{
this.setState({values: valuePrsed});
}
}
render() {
if(this.state.isReady){
return (
<View ref={ref => this.view = ref} onLayout={() => this.saveLayout()}>
</View>
)}else{
<View></View>
}
}
}
To your second question:
If you pass through LoginForm you can create a function there that gets the parameters and updates state, then pass that function to your other component and call the function with the values in paremeter. if you are using react navigation you can do it like so:
loginForm
updateValues(values){
this.setState({value:values})
}
To pass the function with react-navigation:
this.props.navigation.navigate('otherComponent',{updateValues:this.updateValues})
In your otherComponent you call the function like so:
otherComponent
this.props.navigation.state.params.updateValues(newValues);
How about checking for the values variable in the render method?
render() {
console.log("rende splashscreen: ", this.state.values);
let { fadeAnim } = this.state;
return (
this.state.values ?
<View style = {{flex:1}}>
<LoginForm profile = {this.state.values}/>
<Animated.View style={{ ...this.props.style, opacity: fadeAnim }} >
{this.props.children}
<ImageBackground style={styles.logo1} source={require('../../image/dataLogo.jpeg')} >
</ImageBackground>
</Animated.View>
</View>
: <></>
);
}
You can keep a default/initial values in state variable at first like this:
constructor(props){
this.state = {
values:{userName: '', password: ''}
}
}
And when the actual values are available you can set them in state and automatically re-rendering will occur.
Since AsyncStorage returns a promise you can use .then() syntax
componentDidMount(){
console.log("console1");
AsyncStorage.getItem('myKey').then(value=>{
let valuePrsed = JSON.parse(value);
if(valuePrsed.username != null && valuePrsed.password != null)
{
this.setState({values: valuePrsed});
}
}).catch(err=>{
console.log('err', err);
})
}

React Native AsyncStorage not getting the value

constructor(props) {
super(props);
this.state = { data: '' } ;
}
componentWillMount = () => AsyncStorage.getItem('restaurants').then((value) => this.setState({data: value}))
return (
<View>
{this.state.data.map((item) => {
return (
<View>
<Text> {item.name} </Text>
<Text> {item.time} </Text>
</View>
)
})
}
</View>
)
I am trying to get the value in the AsyncStorage, but i keep getting the error: undefined is not a function(evaluating 'this.state.data.map). I been searching the similar topic for a while but I did not find any solution to it. Can someone show me an correct example to do it? Thanks
If You Have stored data in this way
storeData = async () => {
try {
var data ={
restaurants: [
{
name: 'MacD ',
time: "Morning"
},
{
name: 'PizzaHouse',
time: "Evening"
}
]
}
await AsyncStorage.setItem('restaurants', JSON.stringify(data.restaurants))
} catch (error) {
// Error saving data
}
}
constructor(props) {
super(props);
this.state={
fetchingData: true,
data: []
}
}
getData = async()=>{
try {
data = await AsyncStorage.getItem('restaurants');
this.setState({fetchingData: false , data:JSON.parse(data)})
} catch(error){
console.log(error)
}
}
componentDidMount(){
this.getData();
}
renderRestaurant(){
return this.state.data.map((item) => {
return (
<View>
<Text> {item.name} </Text>
<Text> {item.time} </Text>
</View>
)
})
}
render() {
return (
<View style={{width:200, height:200, justifyContent:'center', alignItems:'center', backgroundColor:"blue"}}>
{this.state.fetchingData ? null : this.renderRestaurant()}
</View>
);
};
Try await before AsyncStorage, similar to that or inline
componentWillMount (){
const rest = await AsyncStorage.getItem('restaurants');
}