How to save settings locally on React Native app? - javascript

I'm creating an app on react native with a settings page that allows the user to enable/disbale music and sound settings. I'm using Asyncstorage and states, however whenever I restart the app, the sound settings are not saved and they get initialized to the default value of 'true'. Here is my code below with some screenshots. The image with the music disabled is what I expect to see when I refresh my app
but the image with the music enabled (the default state value) is what I see when reload the app
import { View, Text, StyleSheet, Image, Dimensions, TouchableOpacity, KeyboardAvoidingView,TextInput } from 'react-native'
import React, { useState,useEffect } from 'react'
import Modal from 'react-native-modal';
import colors from '../assets/colors/colors';
import LinearGradient from 'react-native-linear-gradient';
import images from '../assets/images/images';
import { ColorSpace, set } from 'react-native-reanimated';
import AsyncStorage from '#react-native-async-storage/async-storage';
const SettingsModal = (props) => {
const [musicON,setMusicON] = useState(true);
const [soundsON,setSoundsON] = useState(true);
useEffect(()=> {
setData();
//console.log("render");
},[musicON]);
const setData = async() => {
try{
await AsyncStorage.setItem('MUSIC',JSON.stringify(musicON));
console.log("set called");
}
catch(e)
{
console.log("error here");
}
}
const getData = async() => {
let result = await AsyncStorage.getItem('MUSIC');
console.log(result);
}
const toggleMusic = () => {
setMusicON(!musicON);
setData();
};
const toggleSounds = () => {
setSoundsON(!soundsON);
};
return (
<Modal
onBackdropPress={props.setVisibility}
onBackButtonPress={props.setVisibility}
isVisible={props.visibility}
type here
animationIn="bounceInUp"
animationOut="bounceOutDown"
animationInTiming={900}
animationOutTiming={500}
backdropTransitionInTiming={1000}
backdropTransitionOutTiming={500}
style={styles.modalWrapper}
>
{/* Main Modal container here */}
<View style = {styles.modalContentWrapper}>
{/* Gradient outline for container */}
<LinearGradient
colors={[colors.gradHappyPurpleColor1,colors.gradHappyPurpleColor2]}
useAngle = {true}
angle = {90}
style = {styles.modalGradientWrapper}
>
{/* The actual black part where stuff goes */}
<View style = {styles.modalBlackAreaWrapper}>
{/* Settings modal title and subtitle here */}
<View style = {styles.editSettingsTextWrapper}>
<Text style = {styles.editSettingsTitle}>Edit Settings</Text>
<Text style = {styles.editSettingsSubtitle}>(Tap to icons to enable/disable)</Text>
</View>
{/* Selections main wrapper here */}
<View style = {styles.selectionWrapper}>
{/* Music Row wrapper here */}
<View style = {styles.selectionRowWrapper}>
<Text style = {styles.settingLabel}>Music</Text>
<TouchableOpacity onPress={toggleMusic}>
{
musicON === true ? <Image source={images.musicON} style = {styles.emojiIcon}/> : <Image source={images.musicOFF} style = {styles.emojiIcon}/>
}
</TouchableOpacity>
</View>
{/* Sound Row wrapper here */}
<View style = {styles.selectionRowWrapper}>
<Text style = {styles.settingLabel}>Sound Effects</Text>
<TouchableOpacity onPress={toggleSounds}>
{
soundsON === true ? <Image source={images.soundON} style = {styles.emojiIcon}/> : <Image source={images.soundOFF} style = {styles.emojiIcon}/>
}
</TouchableOpacity>
</View>
</View>
</View>
</LinearGradient>
</View>
</Modal>
)
}
export default SettingsModal

Related

Async Storage not working (React native expo), no error given in console, but everytime I reload nothing is stored

I'm trying to use Async Storage for a note app, I created a component called task.js as a template for todos, an navigation.js component for nav, and home.js for the main screen all display with <navigation /> inapp.js, I added a funcction to store object value using async storage, but is not working, everytime I hard reload the app everything will be gone but it is not giving me any errors, I don't know where to start
here is my Home.js
import React, {useState} from 'react';
import { Keyboard, KeyboardAvoidingView, Platform, StyleSheet, Text,
TextInput, TouchableOpacity, View, SafeAreaView, ScrollView, Image } from 'react-native';
import Task from '../components/Task';
import AsyncStorage from '#react-native-async-storage/async-storage';
export default function Home({ navigation }) {
const [task, setTask] = useState();
const [taskItems, setTaskItems] = useState([]);
React.useEffect ( () => {
save(taskItems);
}, [taskItems])
React.useEffect (() => {
getsave();
}, [])
const handleAddTask = () => {
Keyboard.dismiss();
setTaskItems([...taskItems, task])
setTask(null);
}
const completeTask = (index) => {
let itemsCopy = [...taskItems];
itemsCopy.splice (index, 1);
setTaskItems(itemsCopy)
}
const save = async taskItems =>{
try {
const savetask = JSON.stringify(taskItems)
await AsyncStorage.setItem('tasksave', savetask)
} catch (e) {
console.log(e);
}
};
const getsave = async () => {
try {
const taskItems = await AsyncStorage.getItem('tasksave');
if (taskItems != null){
setTaskItems(JSON.parse(taskItems));
}
} catch (error) {
console.log(e);
}
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.tasksWrapper}>
<Text style={styles.sectionTitle}>Your stuff:</Text>
<TouchableOpacity onPress={() => navigation.navigate('About')}>
<Text style={styles.about}>About</Text>
</TouchableOpacity>
<ScrollView style={styles.items}>{
taskItems.map((item, index) => {
return (
<View key={index}>
<TouchableOpacity onPress={ () => navigation.navigate("Gas", {item})}>
<Task text={item} navigation={navigation} />
</TouchableOpacity>
<TouchableOpacity onPress={() => completeTask(index)} style={styles.deleteW}>
<Image style={styles.delete} source={require('../components/remove.png')}></Image>
</TouchableOpacity>
</View>
)
})
}
</ScrollView>
</View>
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.textwrapper}>
<TextInput style={styles.input} placeholder={'message'} value={task} onChangeText={text => setTask(text)}></TextInput>
<TouchableOpacity onPress={() => handleAddTask()}>
<View style={styles.addWrap}>
<Text style={styles.add}>+</Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
Here's my Task.js:
import React from "react";
import { View, Text, StyleSheet, Image, TouchableOpacity } from "react-native";
const Task = (props, {navigation}) => {
return (
<View style={styles.item}>
<View style={styles.itemleft}>
<Image style={styles.lightball} source={require('./arabic.png')}></Image>
<Text style={styles.itemtext}>{props.text}</Text>
</View>
<Image style={styles.arrow} source={require('./rightarrow.png')}></Image>
</View>
)
}
const styles = StyleSheet.create({
export default Task;
I hope is a quick read, I took out all the style stuff but this is still kinda long sorry, if you think it has something to do with my app.js or nav.js I can give you those too, I usually slove these bugs on my own but I just have no idea where to begin cause I'm not getting any error messages, thank you

My audios from firebase realtime database are not playing using touchable opacity in react native after certain iterations/count

I have 29 pronunciations stored in firebase storage and then from there with the help of access token, they're stored in realtime database. In UI, I've touchable opacity (in react native) to play those pronunciations one after the other in order. All pronunciations are getting played really fine and correctly till the 20th pronunciation but as long as i come at the 21st pronunciation, nothing is getting played from there onwards i have no idea why (by the way I have next and back buttons to show my data in order from database). But my other data (Text and images) is displayed correctly and normally, there's only a problem with audios. Can someone help me how to solve this problem? Also I have the same problem whether I use ref().on or ref().once. Here's the code given below:
import React from "react";
import Sound from "react-native-sound";
import database from '#react-native-firebase/database';
import {View, StyleSheet, Text, Image, ToastAndroid, Modal, TouchableOpacity} from 'react-native';
import { useState } from "react";
import { useEffect } from "react";
export default alphl=({navigation})=> {
const [myData,setData] = useState({
letter:'',
word:'',
wmeaning:'',
wimage:'',
apronun:'',
wpronun:'',
});
const [show, setshow]=useState(false);
const [wait, setwait]=useState();
const [img,setimg] = useState(null);
const [apronunn,setapronun] = useState(null);
const [wpronunn,setwpronun] = useState(null);
const [hey,sethey] = useState(1);
function inchey(){
sethey(hey + 1);
}
function decchey(){
sethey(hey - 1);
}
useEffect(() => {
ToastAndroid.showWithGravity('Wait! Loading...', ToastAndroid.LONG, ToastAndroid.CENTER);
getDatabase();
}, [hey]);
function getDatabase() {
database().ref('alphabets/'+hey+'/').once('value' , (snapshot) => {
console.log(snapshot.val());
// Sound.setCategory('Playback', true);
setwait(true);
var poo=new Sound(snapshot.val().apronun);
var pooo=new Sound(snapshot.val().wpronun);
setData({
letter: snapshot.val().letter,
word: snapshot.val().word,
wmeaning: snapshot.val().wmeaning,
wimage: setimg(snapshot.val().wimage),
apronun: setapronun(poo),
wpronun: setwpronun(pooo)
});
setwait(false);
});
// database().ref().off();
}
return (
<Text style={styles.lettertext}>
{myData ? myData.letter : 'loading...' }
</Text>
<TouchableOpacity onPress={() => {
return apronunn.play();
}}
disabled={wait}
style={styles.button}
>
<Text style={styles.buttontext}>Letter Pronunciation</Text>
</TouchableOpacity>
<Text style={styles.toptext}>
Word: {myData ? myData.word : 'loading...' }
</Text>
<Text style={styles.toptext}>
Meaning: {myData ? myData.wmeaning : 'loading...' }
</Text>
<TouchableOpacity onPress={() => {
return wpronunn.play();
}}
disabled={wait}
style={styles.button}
>
<Text style={styles.buttontext}>Word Pronunciation</Text>
</TouchableOpacity>
<Image style={{width:200, height:200, borderRadius:10, marginBottom:15}}
source={{uri: img}}
/>
<View>
<TouchableOpacity onPress={ () => {
if (hey>28) {
ToastAndroid.showWithGravity('Error! This is the last alphabet', ToastAndroid.CENTER, ToastAndroid.CENTER);
}
else {
inchey();
}
}}
style={styles.buttonnb}
>
<Text style={styles.buttontext}>Next</Text>
</TouchableOpacity>
<TouchableOpacity onPress={ async () => {
if (hey<2) {
ToastAndroid.showWithGravity('Error! Can not go back further', ToastAndroid.CENTER, ToastAndroid.CENTER);
}
else {
decchey();
}
}}
style={styles.buttonnb}
>
<Text style={styles.buttontext}>Back</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('alpht')}
style={styles.button}
>
<Text style={styles.buttontext}>Give Test</Text>
</TouchableOpacity>
</View>
</View>
);
}

Expo React Native, How to pick default local images or user image obtained from expo image picker

I have a form that a user can select a default local image or an image from the user's photo library
Here is an expo snack use android the images can be found in the phone menu in photos
I want to save either the default local image or user's image to the form and to redux, currently able to save default images picked to form and redux.
This is what currently works.
I have a component that gets a selected local image and returns an image path witch is a number. That local image gets saved in form and in redux. currently, the user can change the local image in the form.
ImgSelector Component:
import React, { useState } from "react";
import { List, Selector, View, SelectedImg } from "./styles";
import { FlatList } from "react-native";
import { defaultImages } from "../../data/defaultImages";
const FlatlistItem = ({ image, setImg }) => {
return (
<Selector onPress={() => setImg(image)}>
<View>
<SelectedImg source={image} />
</View>
</Selector>
);
};
const ImgSelector = ({ setImg }) => {
const [selectedId, setSelectedId] = useState(null);
const renderItem = ({ item }) => (
<FlatlistItem setImg={setImg} image={item.image} />
);
return (
<View>
<FlatList
horizontal
data={defaultImages}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
extraData={selectedId}
/>
</View>
);
};
export default ImgSelector;
Default local images are stored like this and the path is the index which is a number this part works fine.
export const defaultImages = [
{
id: “2”,
image: require("../assets/images/singlepane.png"),
}
]
I have an imagePicker component that asks for permissions and returns a uri string that looks like this:
file:/data/data/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FExpoWcPro-a828b17b-dcd7-4a04-93ca-657c8e4e511d/ImagePicker/6106d73f-c886-457d-abe9-1f1232a0d398.jpg
My form component where images are picked and saved:
import React, { useState } from "react";
import { Image } from "react-native";
const CounterForm = ({ navigation, ...props }) => {
// This is current state for default images that works
const [imgUrl, setImgUrl] = useState(props.imgUrl || defaultImage);
const [userImgUri, setUserImgUri] = useState(null);
// This gets the local image from a componnet
const handleEditImg = (newImgUrl) => {
setImgUrl(newImgUrl);
};
// This gets image uri from expo image picker
const handelUserImg = (userUri) => {
setUserImgUri(userUri);
};
// This sends data to a redux action to save
const handleSubmit = () => {
props.onFormSubmit({
id: props.id,
imgUrl,
});
setImgUrl(defaultImage);
};
return (
<FormWrapper>
<Row>
<FormButton onPress={() => handleSubmit()}>
<StyledText title="Save" color={COLORS.appBlue} />
</FormButton>
</Row>
<TopContent>
{/* I tried this to get user image and displays in form */}
<Image
source={{ uri: userImgUri }}
style={{ width: 100, height: 100 }}
/>
{/* This current implementation gets local images
<Image
source={imgUrl}
style={{ width: 100, height: 100 }}
/> */}
{/* I tried this only gets local images
{imgUrl ? (
<Image source={imgUrl} style={{ width: 100, height: 100 }} />
) : (
<Image
source={{ uri: userImgUri }}
style={{ width: 100, height: 100 }}
/>
)} */}
</TopContent>
<Row>
<ImagePicker getUserImg={handelUserImg} />
</Row>
<View>
<ImgSelector setImg={handleEditImg} />
</View>
</FormWrapper>
);
};
export default CounterForm;
if you use the last sdk version of Expo (40) and the right package expo-image-picker you need to follow this instructions.
First you need to ask for permissions :
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
}
And then call method to select image from library :
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
So you got image uri by accessing result.uri, you need to save this value (e.g in user store) and display it by selecting your store or default value if there is not stored value :
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Pick an image from camera roll" onPress={pickImage} />
/** imgUrl = stored image uri, defaultImages[0].image = default image uri */
<Image source={imgUrl ? { uri: imgUrl } : defaultImages[0].image} />
</View>
I found the answer it's updated in expo snack
import React, { useState } from "react";
import { List, Selector, View, SelectedImg } from "./styles";
import { FlatList } from "react-native";
import { defaultImages } from "../data";
const FlatlistItem = ({ image, setImg }) => {
return (
<Selector onPress={() => setImg(image)}>
<View>
<SelectedImg source={{uri: image}} />
</View>
</Selector>
);
};
const ImgSelector = ({ setImg }) => {
const [selectedId, setSelectedId] = useState(null);
const renderItem = ({ item }) => {
return (
<FlatlistItem setImg={setImg} image={item} />
)
}
return (
<View>
<FlatList
horizontal
data={defaultImages}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
extraData={selectedId}
/>
</View>
);
};
export default ImgSelector;
Form
import React, { useState } from "react";
import {Asset} from 'expo-asset';
import StyledText from "../UiComponents/StyledText";
import { TouchableWithoutFeedback, Keyboard } from "react-native";
import {
FormWrapper,
TextInputWrapper,
TopContent,
NumberWrapper,
Row,
FormButton,
View,
} from "./styles";
import StyledInput from "../UiComponents/StyledInput";
const defaultImage = Asset.fromModule(require('../assets/komloy.jpg')).uri
import WindowSelector from "../ImgSelector";
import StyledButton from "../UiComponents/StyledButton";
import ImagePicker from "../components/imagePicker";
import { Image } from "react-native";
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
const CounterForm = ({ navigation, ...props }) => {
const [imgUrl, setImgUrl] = useState(props.imgUrl || defaultImage);
const handleEditImg = (newImgUrl) => {
setImgUrl(newImgUrl);
};
const handelUserImg = (userUri) => {
setImgUrl(userUri);
};
const handleSubmit = () => {
props.onFormSubmit({
id: props.id,
imgUrl
});
setImgUrl(defaultImage);
};
return (
<DismissKeyboard>
<FormWrapper>
<TopContent>
<Image
source={{uri: imgUrl}}
style={{ width: 100, height: 100 }}
/>
</TopContent>
<Row>
<StyledText title="Select a image" />
<ImagePicker getUserImg={handelUserImg} />
</Row>
<View>
<WindowSelector setImg={handleEditImg} />
</View>
</FormWrapper>
</DismissKeyboard>
);
};
export default CounterForm;
Data
import {Asset} from 'expo-asset';
const imageURI = Asset.fromModule(require('./assets/islands.jpg')).uri
const imageURI2 = Asset.fromModule(require('./assets/maeYai.jpg')).uri
export const defaultImages = [
imageURI, imageURI2
]

calling a function within a text tag

I think I am getting something wrong, I keep getting an error of 'this.deliveryFareEstimate() is undefined'
I am trying to sum up values gotten from a prop, but its not working as planned, and I think maybe doing it wrong tho. I am roughly new to programming generally.
Below is a sample code I am using to achieve it.
import React, { Component } from "react";
import { View, Text, StyleSheet, Image, TouchableOpacity, SafeAreaView, StatusBar } from "react-native";
import { Ionicons } from "#expo/vector-icons";
import RNSlidingButton, { SlideDirection } from "../../components/RNSlidingButton";
import { Block } from "../../components";
const PerKm = 55;
const PerKg = 35;
export default class ConfirmBooking extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
const { handleBackPress, estimatedWeight, deliveryDuration } = this.props;
FareEstimate = () => {
const totalDistanceCost = PerKm * deliveryDuration;
const totalParcelWeight = PerKg * estimatedWeight;
const estimatedFare = totalParcelWeight + totalDistanceCost;
return estimatedFare;
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.container}>
{/* Delivery Details */}
<View style={styles.header}>
<TouchableOpacity
onPress={handleBackPress}
style={styles.navBarButton}
>
<Ionicons name="md-arrow-back" size={23} color="#FFF" />
</TouchableOpacity>
<Text style={styles.headerText}> Details</Text>
</View>
{/* content holder */}
<View style={styles.content}>
<Block style={styles.generalBlock}>
<Text style={styles.generalBlockHeaderText}>
ETA from Pick up
</Text>
<Text style={styles.generalBlockText}>
{deliveryDuration} Mins
</Text>
</Block>
<Block style={styles.generalBlock}>
<Text style={styles.generalBlockHeaderText}>
Estimated Parcel Weight
</Text>
<Text style={styles.generalBlockText}>{estimatedWeight} Kg</Text>
</Block>
<View style={styles.fareAndConfirm}>
<Text style={styles.fareAndConfirmHeaderText}>Fare</Text>
<Text style={styles.fareAndConfirmText}>
${this.FareEstimate()}
</Text>
</View>
</View>
</View>
</SafeAreaView>
);
}
}
FareEstimate is not properly defined. Always use const or let to define a local variable.
const FareEstimate = () => {
const totalDistanceCost = PerKm * deliveryDuration;
const totalParcelWeight = PerKg * estimatedWeight;
const estimatedFare = totalParcelWeight + totalDistanceCost;
return estimatedFare;
};
Since FareEstimate is defined locally inside render(), Call it without this
<Text style={styles.fareAndConfirmText}>${FareEstimate()}</Text>

React Native: React-Navigation Cannot read property 'navigate' of undefined

I am currently learning React Native and was having some issue with React-navigation.
What I am trying to do is switch screen when the "button" is being pressed.
In the "button", I have:
onPress={() =>
navigate('Home')}
I have const { navigate } = this.props.navigation; before the return statement.
When I run it, I am getting "Cannot read property 'navigate' of undefined.
I guess it is I have to place this.props.navigation somewhere.
Here are my two files:
"IntroPageFive" is the one that has the button and "react-navigation".
I would like to go to "IntroPageOne" when the button is being clicked.
Code for "IntroPageFive":
import React from 'react';
import { Text, View, Image, Linking, Button, TouchableOpacity } from 'react-native';
import PlaceholderImage from '../images/placeholder_thumbnail.png';
import SignInFooter from './signInFooter';
import { createStackNavigator } from 'react-navigation';
import IntroPageOne from './introPageOne';
const App = createStackNavigator({
Home: { screen: IntroPageOne },
});
class IntroPageFive extends React.Component {
render() {
const {
headerTextStyle,
thumbnailStyle,
viewStyle,
subTextStyle,
mainTextSection,
footerSectionStyle,
startButtonStyle,
startButtonTextStyle,
signInButtonStyle ,
signInButtonTextStyle
} = styles;
const { navigate } = this.props.navigation;
return (
<View style={viewStyle}>
<Image style={thumbnailStyle} source={require('../images/placeholder_thumbnail.png')} />
<View style={mainTextSection}>
<Text style={headerTextStyle}>Take A Ride For</Text>
<Text style={headerTextStyle}>Your Favorite Car!</Text>
</View>
<View>
<TouchableOpacity
onPress={() =>
navigate('Home')
}
style={startButtonStyle}
>
<Text style={startButtonTextStyle}>LET'S GET STARTED</Text>
</TouchableOpacity>
</View>
<View style={footerSectionStyle}>
<SignInFooter />
</View>
</View>
);
}
}
export default IntroPageFive;
Here is the code for "IntroPageOne":
import React from 'react';
import { Text, View, Image, Linking } from 'react-native';
import PlaceholderImage from '../images/placeholder_thumbnail.png';
import SignInFooter from './signInFooter';
const IntroPageOne = () => {
const { headerTextStyle, thumbnailStyle, viewStyle, subTextStyle } = styles;
return (
<View style={viewStyle} >
<Image style={thumbnailStyle} source={require('../images/placeholder_thumbnail.png')} />
<Text style={headerTextStyle}>Forget Everything You</Text>
<Text style={headerTextStyle}>Know About Making</Text>
<Text style={headerTextStyle}>Deals For Your Car</Text>
<Text style={subTextStyle}>Deal negotiation powered by AI</Text>
<SignInFooter />
</View>
);
};
};
export default IntroPageOne;
Could anyone please tell me how to fix this issue?
Thank you.

Categories