Unable to access value through SQLite storage in react-native - javascript

I'm trying to access some data input on one page by adding it to sqlite database and then displaying it on another page from the created sqlite database.
The value is not being printed, how can I check if the data is being added to the database in the first place?
I am creating a database and a table, and taking an input value on the home page and passing that to the database.
Next, I navigate to another page and display the data that was previously input from the database.
I don't know how many more details I can add.
import React, {useEffect, useState} from 'react';
import {StyleSheet, View, Text, Pressable, Alert} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import CustomButton from './utils/CustomButton';
import sqlite from 'react-native-sqlite-storage';
import {TextInput} from 'react-native-gesture-handler';
const Stack = createStackNavigator();
const db = sqlite.openDatabase(
{
name: 'MainDB',
location: 'default',
},
() => {},
error => {
console.log(error);
},
);
function ScreenA({navigation}) {
const [info, setInfo] = useState('');
useEffect(() => {
createTable();
getData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onPressHandler = () => {
navigation.navigate('ScreenB');
};
const createTable = () => {
db.transaction(tx => {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS ' +
'Data ' +
'(ID INTEGER PRIMARY KEY AUTOINCREMENT, Info TEXT);',
);
});
};
const getData = () => {
try {
db.transaction(tx => {
tx.executeSql('SELECT Info FROM Data', [], (_tx, results) => {
var len = results.rows.length;
if (len > 0) {
navigation.navigate('ScreenB');
}
});
});
} catch (error) {
console.log(error);
}
};
const setData = async () => {
if (info.length === 0) {
Alert.alert('warning', 'please enter data');
} else {
try {
await db.transaction(async tx => {
await tx.executeSql('INSERT INTO Data (Info) VALUE (?)', [info]);
});
navigation.navigate('ScreenB');
} catch (error) {
console.log(error);
}
}
};
return (
<View style={styles.body}>
<Text style={styles.text}>hello</Text>
<TextInput
style={styles.input}
placeholer="enter your data"
onChangeText={value => setInfo(value)}
/>
<CustomButton
title="go to data"
color="#1eb900"
onPressFunction={setData}
/>
</View>
);
}
function ScreenB({navigation, route}) {
const [info, setInfo] = useState('');
const onPressHandler = () => {
navigation.navigate('ScreenA');
};
useEffect(() => {
getData();
}, []);
const getData = () => {
try {
db.transaction(tx => {
tx.executeSql('SELECT Info FROM Data'),
[],
(_tx, results) => {
let len = results.rows.length;
if (len > 0) {
let userInfo = results.rows.item(0);
setInfo(userInfo);
}
};
});
} catch (error) {
console.log(error);
}
};
return (
<View style={styles.body}>
{/* <Text style={styles.text}>Screen B</Text> */}
<Text style={styles.text}>Welcome {info} </Text>
<Pressable
onPress={onPressHandler}
style={({pressed}) => ({backgroundColor: pressed ? '#ddd' : '#0f0'})}>
{/* <Text style={styles.text}>Go Back to Screen A</Text> */}
</Pressable>
</View>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="ScreenA" component={ScreenA} />
<Stack.Screen name="ScreenB" component={ScreenB} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
body: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
fontSize: 40,
fontWeight: 'bold',
margin: 10,
},
input: {
width: 300,
borderWidth: 1,
borderColor: '#555',
borderRadius: 10,
backgroundColor: '#ffffff',
textAlign: 'center',
fontSize: 20,
marginBottom: 10,
},
});
export default App;

Related

Audio is not automatically closing while pressing backbutton in REACT NATIVE application

In a media player application, I try to use "expo-av" library to build a playlist. everything is working fine. But when I press on the backbutton, it is not behaving properly. I tried in many way. but nothing works for me.
I tried while handling backButton, like, sound.unloadAsync(), sound.stopAsync(), setSound(null).
import React, { useEffect, useState } from 'react';
import {
View,
BackHandler,
Text,
TouchableWithoutFeedback,
StyleSheet,
} from 'react-native';
import * as Progress from 'react-native-progress';
import { connect } from 'react-redux';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { Audio } from 'expo-av';
const sectionsAllCards = [
{
id: 'audio-01',
name: 'Body scan: Generic under mindfulness',
link: 'Bodyscan.m4a',
}
];
const MusicPlayerList = ({ navigation, route, ...props }) => {
const [isPlaying, setIsPlaying] = useState(false);
const [progress, setProgress] = useState(0);
const [audioIndex, setAudioIndex] = useState(0);
const [soundObject, setSoundObject] = useState(null);
const audioSources = [
require('../../assests/musics/Bodyscan.m4a')
];
const togglePlayback = async () => {
if (isPlaying) await soundObject.pauseAsync();
else await soundObject.playAsync();
setIsPlaying(!isPlaying);
};
const onPlaybackStatusUpdate = (status) => {
setProgress(status.positionMillis / status.durationMillis);
};
useEffect(() => {
const loadAudio = async () => {
const source = audioSources[audioIndex];
const sound = new Audio.Sound();
try {
await sound.loadAsync(source);
setSoundObject(sound);
sound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
} catch (error) {
console.log(error);
}
};
loadAudio();
}, [audioIndex]);
async function handleBackButtonClick() {
navigation.navigate('LoginSignup');
return true;
}
useEffect(() => {
BackHandler.addEventListener(
'hardwareBackPress',
handleBackButtonClick,
);
return () => {
BackHandler.removeEventListener(
'hardwareBackPress',
handleBackButtonClick,
);
};
}, []);
const handleOnPress = async (index) => {
if (index === audioIndex) togglePlayback();
else {
setIsPlaying(false);
setProgress(0);
await soundObject.stopAsync();
setSoundObject(null);
setAudioIndex(index);
}
};
return (
<View style={{ backgroundColor: '#efefef', flex: 1 }}>
{sectionsAllCards.map((card, index) => (
<TouchableWithoutFeedback
key={card.id}
onPress={() => handleOnPress(index)}
>
<View style={styles.boxContainer}>
<Text style={styles.audioText}>{card.name}</Text>
<View style={styles.audioIconContainer}>
{progress >= 0 && progress <= 1 && (
<View>
<Progress.Circle
style={styles.progress}
progress={audioIndex === index ? progress : 0}
indeterminate={false}
showsText={false}
size={60}
borderWidth={2}
color={'#479162'}
/>
<Text
style={{
position: 'absolute',
left: 11,
top: 10,
}}
>
<MaterialCommunityIcons
name={
isPlaying && audioIndex === index
? 'pause'
: 'play'
}
size={38}
style={{ color: '#479162' }}
/>
</Text>
</View>
)}
</View>
</View>
</TouchableWithoutFeedback>
))}
</View>
);
};
const styles = StyleSheet.create({
boxContainer: {
},
audioText: {
},
});
const mapStateToProps = (state) => ({
accessToken: state.auth.accessToken,
});
export default connect(mapStateToProps, {})(MusicPlayerList);

Trying to come out with a filter function for my app. Render Error: Too many re-renders. React limits the number of renders

The idea I have for this to work is to copy my main array from firebase (Array with all my info) into a temporary array. Then I will filter this temporary array and have it displayed in flatlist. The onPress for the buttons serves to select the type of information to be filtered (Eg type 1 or 2 or 3).
import React, { useState, setState, useEffect } from 'react';
import { View, Text, StyleSheet, ImageBackground, FlatList, Button, TouchableHighlight } from 'react-native'
import Card from '../components/Card';
import colors from '../config/colors';
import {MaterialCommunityIcons} from '#expo/vector-icons'
import { useNavigation } from '#react-navigation/core';
import AppButton from '../components/AppButton'
import { SearchBar } from 'react-native-screens';
import { Firestore, getDoc, collection, getDocs,
addDoc, deleteDoc, doc,
query, where, onSnapshot
} from 'firebase/firestore';
import {db} from '../../firebase';
import { async } from '#firebase/util';
//run: 1
//swim: 2
//cycle: 3
function EventsPage(props) {
const [events, setEvents] = useState([]);
const [bool, setBool] = useState(false);
const [arr, setArr] = useState([])
const colRef = collection(db, 'events');
const q = query(colRef, where('type', '>=', 0))
onSnapshot(q, (snapshot) => {
const events = []
snapshot.docs.forEach((doc) => {
events.push({...doc.data()}) //put the data into an array
})
if (bool === false) {
setEvents(events);
setBool(true)
}
})
const updateSearch = search => {
setArr({ search }, () => {
if (type == search) {
setArr({
data: [...arr.temp]
});
return;
}
arr.data = arr.temp.filter(function(item){
return item.name.includes(search);
}).map(function({date, subTitle, title, type}){
return {date, subTitle, title, type};
});
});
};
return (
<View style = {styles.container}>
<ImageBackground
source = {require('../assets/splash-page.jpg')}
style = {{width: '100%', height: '100%'}}
blurRadius={8}
>
<View style = {styles.backIcon}>
<MaterialCommunityIcons name='arrow-left-bold' color="black" size={35} onPress={() => {
navigation.replace("Connect_me")
}} />
</View>
<Text style = {styles.text}>EVENTS</Text>
<View style = {styles.buttons}>
<Button title={'All'} />
<Button title={'Run'} onPress = {updateSearch(1)}/>
<Button title={'Swim'} onPress = {updateSearch(2)}/>
<Button title={'Cycle'} onPress = {updateSearch(3)}/>
</View>
<FlatList
data={arr.data}
renderItem={({ item }) => (
<View style = {styles.cardContainer}>
<Card title={item.title} subTitle = {item.subTitle}/>
</View>
)}
/>
<Text></Text>
<Text></Text>
<Text></Text>
<Text></Text>
<Text></Text>
</ImageBackground>
</View>
// trolling
);
}
const styles = StyleSheet.create({
text: {
fontSize: 80,
textAlign:'center',
paddingBottom: 20,
color: colors.primary,
fontWeight: 'bold',
},
container: {
backgroundColor: 'white',
},
cardContainer: {
width: '95%',
alignSelf: 'center'
},
backIcon: {
paddingLeft: 10,
paddingTop: 30,
},
searchIcon: {
paddingLeft: 10,
paddingTop: 15,
position: 'relative',
left: 330,
bottom: 47
},
buttons: {
flexDirection: 'row',
padding: 20,
}
})
export default EventsPage;
Side effects code like listening to data change events should be handled inside the useEffect hook.
The app continues to listen to data change events for each component re-render which causes an infinity loop.
useEffect(() => {
const unsubscribe = onSnapshot(q, (snapshot) => {
const events = [];
snapshot.docs.forEach((doc) => {
events.push({ ...doc.data() }); //put the data into an array
});
if (bool === false) {
setEvents(events);
setBool(true);
}
});
// unsubscribe to data change events when component unmount
return () => {
unsubscribe();
};
}, []);

Error querying the api: This works in the web browser but not on mobile. (expo)

I'm new to react native and I'm not able to consume this api, when I start this app in the browser, it works fine, but when I go to the expo app it doesn't display the pokemon image, could someone help me?
import { StatusBar } from 'expo-status-bar';
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View, Button, Alert, TextInput, Image } from 'react-native';
interface PokeInterface {
sprites : {
back_default : string;
}
}
export default function App() {
const [text, setText] = useState<string>("")
const [response, setResponse] = useState<PokeInterface | any>()
const [image, setImage] = useState<string>()
const handleText = (text : string) => {
setText(text)
}
const searchApi = (pokemonName : string) => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}/`, { method: 'GET'})
.then((response) => response.json())
.then((response) => setResponse(response))
}
useEffect(() => {
if(text){
searchApi(text)
}
if(response){
const {sprites} = response
setImage(sprites.front_default)
}
return () => {
if(image){
setImage("")
}
}
},[text, response])
return (
<View style={styles.container}>
<View style={styles.topbar}>
<Text style={styles.title}>Pokedex Mobile</Text>
<TextInput
style={styles.input}
onChangeText={(value: any) => handleText(value)}
value={text}
placeholder="Search Pokemon"
keyboardType="default"
/>
<Text style={styles.text}>{text}</Text>
</View>
{image && (
<Image
style={styles.logo}
source={{uri : `${image}`}}
/>
)}
</View>
);
}
const styles = StyleSheet.create({
text : {
fontSize: 30,
color : "red"
},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
},
container : {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
title: {
fontSize: 30,
color: '#000'
},
topbar: {
},
logo : {
width: 200,
height: 200
}
});
Your current code causes an infinite loop...
You type some text which triggers searchApi(text)
That writes to response which triggers your effect hook
Because text is still truthy, it triggers searchApi(text) again
Goto #2
As far as I can tell, you can simply discard most of response and just retrieve the image when the text changes.
// this doesn't need to be defined in your component
const getPokemonImage = async (name: string) => {
const res = await fetch(
`https://pokeapi.co/api/v2/pokemon/${encodeURIComponent(pokemonName)}/`
);
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
return (await res.json<PokeInterface>()).sprites.front_default;
};
export default function App() {
const [text, setText] = useState<string>("");
const [image, setImage] = useState<string>(""); // initial value
const handleText = (text: string) => {
setText(text);
};
useEffect(() => {
if (text) {
getPokemonImage(text)
.then(setImage)
.catch(err => {
console.error("getPokemonImage", err)
// show an error message or something
});
}
}, [ text ]); // only run on text change
import React, {useEffect, useState} from 'react';
import {StyleSheet, Text, View, TextInput, Image, Button} from 'react-native';
// Sorry for removing the types i was using JS
// This code works test it for yourself
export default function App() {
const [text, setText] = useState('');
const [response, setResponse] = useState(); // Here use PokeInterface || any as you are doing conditional checking
const [image, setImage] = useState();
const handleText = e => {
setText(e);
};
const searchApi = pokemonName => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}/`, {method: 'GET'})
.then(response => response.json())
.then(response => setResponse(response));
};
useEffect(() => {
if (response) {
const {sprites} = response;
console.log(response);
setImage(sprites.front_default);
}
return () => {
if (image) {
setImage('');
}
};
}, [image, text, response]); // you have to pass all the dependencies so useEffect will be invoked as you didnt pass image dep the useeffct was not invoking
return (
<View style={styles.container}>
<View style={styles.topbar}>
<Text style={styles.title}>Pokedex Mobile</Text>
<TextInput
style={styles.input}
onChangeText={(value: any) => handleText(value)}
value={text}
placeholder="Search Pokemon"
keyboardType="default"
/>
<Text style={styles.text}>{text}</Text>
</View>
{image && <Image style={styles.logo} source={{uri: `${image}`}} />}
<Button
title={'Submit'}
onPress={() => searchApi(text)}
disabled={!text}
/>
</View>
);
}
const styles = StyleSheet.create({
text: {
fontSize: 30,
color: 'red',
},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
},
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 30,
color: '#000',
},
topbar: {},
logo: {
width: 200,
height: 200,
},
});

React-Native Key Error - All Elements are deleted even though there is a unique key added to the KeyExtractor

I am adding a unique key to the FlatList and in theory only the button i press is supposed to be deleted but instead all elements are deleted
import { render } from "react-dom";
import {
View,
Text,
StyleSheet,
FlatList,
Button,
TouchableOpacity,
} from "react-native";
import { Context } from "../context/BlogContext";
import { Entypo } from "#expo/vector-icons";
const IndexScreen = function () {
const { state, addBlogPost, deleteBlogPost } = useContext(Context);
return (
<View>
<Button title="Add Post" onPress={() => addBlogPost()} />
<FlatList
data={state}
keyExtractor={(blogPosts) => blogPosts.title}
renderItem={({ item }) => {
return (
<View style={styles.row}>
<Text style={styles.title}>
{item.title} - {item.id}
</Text>
<TouchableOpacity
onPress={() => {
deleteBlogPost(item.id);
}}
>
<Entypo style={styles.icon} name="trash" />
</TouchableOpacity>
</View>
);
}}
/>
</View>
);
};
const styles = StyleSheet.create({
row: {
flexDirection: "row",
justifyContent: "space-between",
paddingHorizontal: 10,
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "gray",
},
title: {
fontSize: 18,
},
icon: {
fontSize: 24,
},
});
export default IndexScreen;
Context Screen:
import createDataContext from "./createDataContext";
const blogReducer = function (state, action) {
switch (action.type) {
case "delete_blogpost":
return state.filter((blogPosts) => {
blogPosts.id !== action.payload;
});
case "add_blogpost":
return [
...state,
{
id: Math.floor(Math.random() * 99999),
title: `Blog Post #${state.length + 1}`,
},
];
default:
return state;
}
};
const addBlogPost = function (dispatch) {
return () => {
dispatch({ type: "add_blogpost" });
};
};
const deleteBlogPost = (dispatch) => {
return (id) => {
dispatch({ type: "delete_blogpost", payload: id });
};
};
export const { Context, Provider } = createDataContext(
blogReducer,
{ addBlogPost, deleteBlogPost },
[]
);
and
export default function (reducer, actions, initialState) {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
// actions === { addBlogPost : (dispatch) => {return () => {}}}
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
);
};
return { Context, Provider };
}
i dont know how to solve this. all titles are unique as they have different numbers but still all are deleted!!!!!!!!!!!!
here is the pic of the app

undefined is not an object (evaluating 'item.Title') in React Native

So I was making this movie browser project in which I had to fetch data from OMDb API(http://www.omdbapi.com/) and display the data in a Flatlist component.
Although I managed to display 10 results of every movie searched for(as API return 10 items on every call), I added a button that would run a function to send a request again to the API using the page parameter, fetch 10 more results and concatenate the results to the movies.
But as soon as I press the button and run the function, this error appears undefined is not an object (evaluating 'item.Title').
This is my code for the Home Component => Home.js
import React, { useState, useEffect } from 'react';
import { StyleSheet, View, Text, FlatList, TouchableHighlight, Image, Button} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { fetchMovies } from "../api/api";
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
movies: null,
};
}
//update search text
componentDidUpdate(prevState) {
if (this.state.text !== prevState.text) {
this.getSearch(this.state.text);
}
}
//get search results from fetchMovies
getSearch = async text => {
const results = await fetchMovies(text)
this.setState({ movies: results });
};
////////////////////////////Function making API call using the page parameter///////////
//loading more movies
handleLoadMore = async() => {
try {
const page = Math.trunc(this.state.movies.length / 10) + 1;
const res = await fetchMovies(this.state.text, page);
this.setState(prevState => ({
movies: prevState.movies.concat(res.movies)
}))
}catch(err){
console.log(err.message);
}
}
//////////////////////////////////////////////////////////
//movie title and poster to render in the flatlist
movieCard = ({ item }) => {
return (
<TouchableHighlight
style={styles.movieCard}
underlayColor="white"
onPress={() => {
this.props.navigation.navigate("Details", {
title: item.title,
id: item.imdbID
});
}}
>
<View>
<Image
style={styles.movieImage}
source={ {uri: item.Poster} }
/>
<View style={{alignItems: 'center'}}>
<Text style={styles.movieTitle}>{item.Title} ({item.Year})</Text>
</View>
</View>
</TouchableHighlight>
);
};
render() {
return(
<View style={styles.container}>
<TextInput
style={styles.searchBox}
autoCorrect={false}
autoCapitalize='none'
autoFocus maxLength={45}
placeholder='Search'
onChangeText={(text) => this.setState({ text })}
value={this.state.text}
/>
{this.state.movies ?
<FlatList
style={styles.movieList}
data={this.state.movies}
renderItem={this.movieCard}
keyExtractor={item => item.Title + item.imdbID}
/>
:
<Text
style={{
alignSelf: 'center',
paddingTop: 150,
justifyContent: 'center',
color: '#8a8787',
fontStyle: 'italic' }}>
search for a movie above...
</Text>
}
<Button
onPress={this.handleLoadMore}
title="Load More"
color="#841584"
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#DDD',
alignItems: 'center',
},
searchBox: {
fontSize: 20,
fontWeight: '300',
padding: 10,
width: '100%',
backgroundColor: 'white',
borderRadius: 10,
marginBottom: 30
},
movieList: {
flex: 1,
marginHorizontal: 30,
},
movieCard: {
flex: 1,
margin: 5,
padding: 5,
},
movieImage: {
width: '100%',
height: 350,
borderRadius: 10,
alignSelf: 'center',
},
movieTitle: {
marginTop: 10,
fontSize: 20,
color: '#333'
}
});
This is the code for api functions => api.js
const API_KEY = "API_KEY";
//fetch search data from omdb api
export const fetchMovies = async (response, page) => {
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&s=${response}`;
try {
let response = await fetch(url);
if(page) {
response = await fetch(url + `&page=${page}`)
}
const { Search } = await response.json();
return Search;
} catch (err) {
return console.log(err);
}
};
//fetch ID from omdb api
export const fetchById = async id => {
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&i=${id}`;
try {
const response = await fetch(url);
const results = await response.json();
return results;
} catch (err) {
return console.log(err);
}
};
I know solution to this is probably simple but being new to react-native I am not able to figure it out.
regarding FlatList, In docs they apparently pass lambda which returns rendered items to renderItem prop
Also your initialized state.movies is null and i think it should be an empty array
this.state = {
text: "",
movies: [],
};
<FlatList
style={styles.movieList}
data={this.state.movies}
renderItem={({item}) => this.movieCard({item})}
keyExtractor={item => item.Title + item.imdbID}

Categories