How can I store multiple data using asyncstorage in React Native? - react-native

I have used the asyncstorage for storing the data but I think it's storing only one entry at a time that's because when I tried to print the value it only showed the last signup details and the too only on console instead of screen.
What I want:
Store data of all the users.
Print all the details on the screen.
Due to formatting issue I was not able to attach the code. Please check my code on this link.

Async storage isnt really meant for state management. Its for having data that will persist between app opens and closes. Some examples of this is using it to save a user auth token, or to keep track of the user defined settings.
Here's a quick demo
import { useState, useEffect } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { TextInput, Button } from 'react-native-paper';
import Constants from 'expo-constants';
import AsyncStorage from '#react-native-async-storage/async-storage';
const someDataKey = '#someData';
export default function App() {
const [someData, setSomeData] = useState({
token: null,
userId: null,
expiresAt: '',
});
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const submit = () => {
// fake server call to get token
setSomeData({
token:getRandomChars(50),
userId:Math.floor(Math.random()*1000)+1,
expiresAt:Date.now()+60*60*24*4
})
};
useEffect(() => {
const getData = async () => {
const dataAsString = await AsyncStorage.getItem(someDataKey);
if (dataAsString) setSomeData(JSON.parse(someData));
};
getData();
}, []);
useEffect(()=>{
AsyncStorage.setItem(someDataKey,JSON.stringify(someData))
},[someData])
return (
<View style={styles.container}>
{!someData.token ? (
<>
<TextInput
value={email}
label="Enter email"
onChangeText={setEmail}
style={styles.input}
dense
/>
<TextInput
value={password}
label="Password"
onChangeText={setPassword}
style={styles.input}
dense
/>
<Button onPress={submit}>Login</Button>
</>
) : (
<>
<Text>Last session retrieved</Text>
<Text>Token:{someData.token}</Text>
<Text>User ID:{someData.userId}</Text>
<Button onPress={()=>{
setSomeData({})
}}>Reset data</Button>
</>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
input: {
marginBottom: 10,
},
});
const getRandomChars = (len=20)=>{
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
let str =''
while(str.length <len){
const index = Math.floor(Math.random()*chars.length)
str+=chars[index]
}
return str
}
Before the data was saved to storage, reloading the page would show the login form; but once the data is set, the data is retrieved, omitting the login part

Related

React Native DateTimePickerModal from "react-native-modal-datetime-picker" Not letting me add 2 DateTime picker in one component

I need to add 2 DateTimePicker to my component in my React-native app. But only one work even if i add 2. I can open each datetimepicker but only one value change that is the top one. So can select bottom one and will only change the top value. See the code below
import React, { useState } from 'react';
import { Button, View, Text } from 'react-native';
import DateTimePickerModal from 'react-native-modal-datetime-picker';
import moment from 'moment';
const Example = () => {
const [selectedDate, setSelectedDate] = useState();
const [selectedDate1, setSelectedDate1] = useState();
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
const showDatePicker = () => {
setDatePickerVisibility(true);
};
const hideDatePicker = () => {
setDatePickerVisibility(false);
};
const handleConfirm = (date) => {
setSelectedDate(date);
hideDatePicker();
};
const handleConfirm1 = (date) => {
setSelectedDate1(date);
hideDatePicker();
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{`Date: ${selectedDate? moment(selectedDate).format("MM/DD/YYYY"):"Please select date"}`}</Text>
<Button title="Show Date Picker" onPress={showDatePicker} />
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
onConfirm={handleConfirm}
onCancel={hideDatePicker}
/>
<Text>{`Date: ${selectedDate1? moment(selectedDate1).format("MM/DD/YYYY"):"Please select date"}`}</Text>
<Button title="Show Date Picker" onPress={showDatePicker} />
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
onConfirm={handleConfirm1}
onCancel={hideDatePicker}
/>
</View>
);
};
export default Example;
So I am wondering if it is even possible to add 2 DateTimePicker into one component?
It looks like there is only 1 state handling the opening of the pickers which is causing the first to open each time
const [isDatePickerVisibleOne, setDatePickerVisibilityOne] = useState(false)
const [isDatePickerVisibleTwo, setDatePickerVisibilityTwo] = useState(false)

React Native - searchApi is not a function

I am new in React Native. I try to create a simple searching food restaurant with Yelp. Unfortunately, I get an error:
"searchApi is not a function. (in 'searchApi(term)', 'searchApi' is
"")
Below my code.
useResults.js
import React, { useEffect, useState } from 'react';
import yelp from '../api/yelp';
export default () => {
const [result, setResult] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const searchApi = async (searchTerm) => {
console.log("hi there");
try {
const response = await yelp.get('/search', {
params: {
limit: 50,
term: searchTerm,
location: 'san jose'
}
});
setErrorMessage(null);
setResult(response.data.businesses);
} catch (err) {
setErrorMessage('Something Went Wrong');
}
};
/*
useEffect(() => {}); //Run the arrow function everytime the component is rendered
useEffect(() => {}, []); // Run the arrow function only when the component is first rendered
useEffect(() => {}, [value]); // Run the arrow function only when the component is first rendered, and when the value is changes
*/
useEffect(() => {
searchApi('pasta');
}, []);
return [searchApi, result, errorMessage];
};
SearchScreen.js
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import ResultList from '../components/ResultList';
import SearchBar from '../components/SearchBar';
import useResults from '../hooks/useResults';
const SearchScreen = () => {
const [term, setTerm] = useState('');
const [searchApi, result, errorMessage] = useResults();
console.log(result);
return (
<View>
<SearchBar
term={term}
onTermChange={setTerm}
onTermSubmit={() => searchApi(term)}
/>
<View>{errorMessage ? <Text>{errorMessage}</Text> : null}</View>
<Text>We have found {result.length} results</Text>
<ResultList title="Cost Effective" />
<ResultList title="Bit Pricier" />
<ResultList title="Big Spender"/>
</View>
);
};
const styles = StyleSheet.create({
});
export default SearchScreen;
edit :
SearchBar.js
import React from 'react';
import { View, Text, StyleSheet, TextInput } from 'react-native';
import { Feather } from '#expo/vector-icons';
const SearchBar = ({ term, onTermChange, onTermSubmit }) => {
return (
<View style={styles.backgroundStyle}>
<Feather style={styles.iconStyle} name="search" size={30} color="black" />
<TextInput style={styles.inputStyle}
autoCapitalize="none"
autoCorrect={false}
placeholder="Search"
value={term}
onChangeText={onTermChange}
onEndEditing={onTermSubmit}
/>
</View>
)
};
const styles = StyleSheet.create({
backgroundStyle: {
marginTop: 10,
backgroundColor: '#F0EEEE',
height: 50,
borderRadius: 5,
marginHorizontal: 15,
flexDirection: 'row'
},
inputStyle: {
flex: 1,
fontSize: 18,
marginHorizontal: 10
},
iconStyle: {
fontSize: 35,
alignSelf: 'center'
}
});
export default SearchBar;
When I type in search bar and hit done button, I got the error above.
Seems in useResults.js file this: return [searchApi, result, errorMessage]; does not properly return the function. But the result and errorMessage return successfully.
And in this file: SearchScreen.js the error line is shown in here: onTermSubmit={() => searchApi(term)}.
How to fix this?
Try adding a callback to onChangeText.
<TextInput style={styles.inputStyle}
autoCapitalize="none"
autoCorrect={false}
placeholder="Search"
value={term}
onChangeText={() => onTermChange()} // Add fat arrow function here
onEndEditing={onTermSubmit}
/>

Async storage doesnt display when i reload

I am VERY VERY new to React Native. i have never posted on a forum, sorry if formatting is incorrect. Please bear with me. When i store a value using Async, i write to the console, so i know it is storing the value, then i read back the value and i know it is there when i read from the console but it wont set my radio button to the value stored using Async. The first line of these 4 does NOT work even though i KNOW the data is set but the 3 commented out lines each work fine if i test them separately but it is the first line i want to work:
const [checked, setChecked] = useState(getData());
// const [checked, setChecked] = useState('first');
//const [checked, setChecked] = useState('second');
//const [checked, setChecked] = useState(params.startvalue);
Here is full code:
import React, { useState , useEffect} from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import Constants from 'expo-constants';
import AsyncStorage from '#react-native-async-storage/async-storage';
// or any pure javascript modules available in npm
import { RadioButton } from 'react-native-paper';
const storeData = async (value) => {
try {
console.log("in storeData value is-->" + value.toString());
await AsyncStorage.setItem('#storage_Key', value.toString())
} catch (e) {
console.log("didntwork in StoreData");
}
}
const getData = async () => {
try {
const value = await AsyncStorage.getItem('#storage_Key');
console.log("value in getData is:", value.toString());
return value != null ? value.toString() : null;
} catch (e) {
console.log("error in getData", { e });
}
}
const MyRadioButton = params => {
const [checked, setChecked] = useState(getData());
// const [checked, setChecked] = useState('first');
//const [checked, setChecked] = useState('second');
//const [checked, setChecked] = useState(params.startvalue);
return (
<View>
<Text>{params.startvalue}</Text>
<Text>{params.message1}
<RadioButton
value="first"
status={checked == 'first' ? 'checked' : 'unchecked'}
onPress={() => {
setChecked('first');
params.setxDisabled(true);
storeData('first');
}
}
/></Text>
<Text>{params.message2}
<RadioButton
value="second"
status={checked == 'second' ? 'checked' : 'unchecked'}
onPress={() => {
setChecked('second');
params.setxDisabled(false);
storeData('second');
}
}
/></Text>
</View>
);
};
export default function App() {
const [xdisabled, setxDisabled] = useState(true);
return (
<View style={styles.container}>
<Text style={styles.auto} >Welcome </Text>
<Text style={styles.auto} >Blah Blahhhh</Text>
<MyRadioButton message1="I do NOT agree to the terms" message2="I agree to the terms" setxDisabled={setxDisabled} startvalue="first" />
<Button title="continue" disabled={xdisabled} onPress={() => navigation.navigate('Home')} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
Okay so if I understand you correctly you want to load the current state from AsyncStorage. You are never actually getting the value from AsyncStorage on loading the page because it is an async function. You need to await the return value.
I recommend using useEffect() for this task to immitate a component mount. You should import it from from react.
Try something like this:
const [checked, setChecked] = useState('default value');
useEffect(() => {
const asyncWrap = async () => {
const value = await getData();
setChecked(value);
}
asyncWrap() // you can't make async calls directly in useEffect
}, []); // <-- empty [] is very important!
You can now use the state as usual.

Add a loader for authentication flow on React Native Expo

I just added the loader that is loaded when the user sends the request to login by clicking the button with this code:
import React, { useState } from 'react';
import { Text, TextInput, SafeAreaView, StyleSheet, TouchableOpacity, Image, KeyboardAvoidingView, ActivityIndicator } from 'react-native';
import {AuthContext} from './utils';
// Creating Login Activity.
export function SignInScreen() {
const [isLoading, setLoading] = useState(false);
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const { signIn } = React.useContext(AuthContext);
return (
<KeyboardAvoidingView behavior={Platform.OS == 'ios' ? 'padding' : 'height'} style={styles.keyboard_login}>
<SafeAreaView style={styles.contenitore_login}>
{isLoading == true ? <ActivityIndicator size="large"/> : (
<>
<Image style={styles.logo} source={require('../assets/logo.png')} />
<TextInput
style={styles.campo_login}
placeholder="Email"
value={email}
onChangeText={setEmail}
autoCapitalize='none'
textContentType='emailAddress'
keyboardType='email-address'
/>
<TextInput
style={styles.campo_login}
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
/>
<TouchableOpacity style={styles.cta_login} onPress={() => { setLoading(true); signIn({ email, password });}}>
<Text style={styles.testo_cta_login}>Accedi</Text>
</TouchableOpacity>
</>
)}
</SafeAreaView>
</KeyboardAvoidingView>
);
}
Everything works perfectly when the user enters the correct email and password, but when they enter the wrong credentials the loader keeps going.
}).then((response) => response.json()).then((responseJson) => {
// If server response message same as Data Matched
if(responseJson === 'Data Matched'){
dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
}else{
Alert.alert(responseJson);
}
}).catch((error) => {
console.error(error);
});
As you can see if the fetch URL says "Data Matched" then it is assigned SIGN_IN which then returns the user to the home of my app, but in the case where the logins don't match I don't know what to do to send the user back to the login page.
What is the navigation code that is used in this case? Thanks!
We can have variable let's say loading
const [loading, setLoading] = useState(false)
And as far I can see your Sigin function connects to db. So do something like
const authContext = React.useMemo(
() => ({
signIn: async data => {
setLoading(true);
// Some code here
setLoading(false);
}
})
)
And then show an Activity indicator or any component you want to show fetching something like this
import React from 'react';
import PropTypes from 'prop-types';
import {View, ActivityIndicator, Modal} from 'react-native';
import styles from './Styles/FullScreenLoaderStyles';
const FullScreenLoader = ({loading}) => (
<Modal transparent={true} animationType={'none'} visible={loading}>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorWrapper}>
<ActivityIndicator color="#000" animating={loading} />
</View>
</View>
</Modal>
);
FullScreenLoader.propTypes = {
loading: PropTypes.bool,
};
export default FullScreenLoader;
I have updated the loading screen code. Now you can import this in your google signin screen like
import FullScreenLoader from './FullScreenLoader';
// some code
return(
<View>
<FullScreenLoader loading={isLoading} />
</View>
)
FullScreenLoaderStyles.js
import {StyleSheet} from 'react-native';
import colors from '../../Themes/Colors';
export default StyleSheet.create({
modalBackground: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#00000040',
},
activityIndicatorWrapper: {
backgroundColor: colors.grey,
height: 50,
width: 50,
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center',
},
});

Unable to store data in redux store -Data disappears after refreshing the page

I am new to react-native and learning react-redux. I went to a website and copied the exact code. The code is not storing values of email and password. When I refresh the page all the data disappears. Can anyone help me to save data in redux-store persistently? Any help would be highly appreciated.
Here is my App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from '../redux/store';
import Form from './components/Form';
export default function App() {
return (
<Provider store={store}>
<Form />
</Provider>
);
}
And my Form.js
import React from 'react';
import { View, Button, TextInput, StyleSheet } from 'react-native';
import { Field, reduxForm } from 'redux-form';
const Form = (props) => {
const { handleSubmit } = props;
const onSubmit = (values) => console.log(values);
const renderInput = ({ input: { onChange, ...input }, ...rest}) => {
return <TextInput style={styles.input} onChangeText={onChange} {...input} {...rest} />
};
return (
<View style={styles.root}>
<Field
name={'email'}
props={{
placeholder: 'Email'
}}
component={renderInput}
/>
<Field
name={'password'}
props={{
placeholder: 'Password',
secureTextEntry: true
}}
component={renderInput}
/>
<Button title={'Submit'} onPress={handleSubmit(onSubmit)} />
</View>
);
};
const styles = StyleSheet.create({
root: {
flex: 1,
padding: 32,
justifyContent: 'center'
},
input: {
padding: 8,
marginBottom: 8,
borderColor: 'blue',
borderWidth: 1,
borderRadius: 4
}
});
export default reduxForm({form: 'test-form'})(Form);
My store.js
import {combineReducers, createStore} from 'redux';
import {reducer as formReducer} from 'redux-form';
const rootReducer = combineReducers({
form: formReducer
});
const store = createStore(rootReducer);
export default store;
To persist your data you need to use redux-persist.
here is the Github link