React Native - Navigating two screen using two different fetch request - javascript

I'm new in react native. I'm creating a flatlist which contains a category buttons of foods, and once click a category button a second page will be display containing a kinds of foods depending on what category button the user clicks.
The names of the category button is load from my database, so I have a fetch for that. Now, as I've said I have to display a second page once a button is clicked.
I've already done a code where there is 2 kinds of fetch request for displaying my category name in the button and for navigating to the second page using the other fetch.
The problem is; once a category button is clicked, my button won't display any second page.
Here is my code
categories.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity
} from 'react-native';
var screen = Dimensions.get('window');*/
export default class Categories extends Component {
static navigationOptions = {
title: 'Product2'
};
state = {
data: [],
};
fetchData = async() => {
const response_Cat = await fetch('http://192.168.254.102:3307/Categories/');
const category_Cat = await response_Cat.json();
this.setState({data: category_Cat});
};
componentDidMount() {
this.fetchData();
};
FoodCat = async() => {
const { params } = this.props.navigation.navigate('state');
const response_Food = await fetch('http://192.168.254.102:3307/foods/' + params.id);
const food_Food = await response_Food.json();
this.setState({data: food_Food});
};
componentDidCatch() {
this.FoodCat();
};
render() {
const { navigate } = this.props.navigation;
const { params } = this.props.navigation.navigate('state');
return (
<View style = { styles.container }>
<FlatList
data = { this.state.data }
renderItem = {({ item }) =>
<TouchableOpacity style = {styles.buttonContainer}>
<Text style = {styles.buttonText}
onPress = { () => navigate('FoodCat', { id: item.id }) }>{ item.cat_name }</Text>
</TouchableOpacity>
}
keyExtractor={(x,i) => i}
/>
</View>
);
}
}
AppRegistry.registerComponent('Categories', () => Categories);
Details.js
import React, {Component} from 'react';
import { AppRegistry, StyleSheet,
FlatList, Text, View }
from 'react-native';
export default class Details extends Component {
constructor() {
super()
this.state = {
dataSource: []
}
}
renderItem = ({ item }) => {
return (
<View style = {{flex: 1, flexDirection: 'row'}}>
<View style = {{flex: 1, justifyContent: 'center'}}>
<Text>
{item.menu_desc}
</Text>
<Text>
{item.menu_price}
</Text>
</View>
</View>
)
}
componentDidMount() {
const url = 'http://192.168.254.102:3307/foods/'
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
dataSource: responseJson.data
})
})
.catch((error) => {
console.log(error)
})
}
render(){
console.log(this.state.dataSource)
const { params } = this.props.navigation.navigate('state');
return (
<View style = { styles.container }>
<FlatList
data = { this.state.dataSource }
renderItem = {this.renderItem}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
AppRegistry.registerComponent('Details', () => Details);

Related

Trying to get the title on the header, but unable to do so

I am trying to get the title on the header on my react native application. i have been following a video lecture, but I till can't seem to get it right
import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
import { DOC } from '../Data/dummy-data'
const Doctors = props => {
// destructure
const { docId } = props.route.params
const selectedCategory = DOC.find(doc => doc.id === docId)
return (
<View style={styles.screen}>
<Text>{selectedCategory.title}</Text>
</View>
)
}
Doctors.navigationOptions = (navigationData) => {
const docId = navigationData.navigation.getParam('docId')
const selectedCategory = DOC.find(doc => doc.id === docId)
return {
headerTitle:selectedCategory.title
}
}
export default Doctors
const styles = StyleSheet.create({
screen:{
flex:1,
justifyContent:'center',
alignItems:'center'
}
})

useState array is undefined even though it is initialized as empty array

I'm working in a React Native Expo project with Firebase v9 and I'm getting an error because of my state variabel categories(I think that's the issue).
This component allows the user to add categories to a flatlist, which is seen here:
As it shows i'm already getting an warning which says: '[Unhandled promise rejection: FirebaseError: Function setDoc() called with invalid data. Unsupported field value: undefined (found in field categories in document users/Hk4k6fKrtZZG1BGffFrOTRvuT2h2)]'
And when i add a category i get the error -> Render error: undefined is not an object(evaluating 'iter[symbol.iterator]')
This is the code for my CategoryComponent:
import { StyleSheet, View, FlatList, Alert, Animated} from 'react-native'
import React, { useState, useEffect} from 'react'
import { db, } from '../../firebase/firebase'
import { doc, setDoc, onSnapshot} from 'firebase/firestore';
import firebase from 'firebase/compat/app';
import { Button, Divider, Subheading, Text, Modal, Portal, TextInput } from 'react-native-paper';
import Swipeable from 'react-native-gesture-handler/Swipeable'
import { TouchableOpacity } from 'react-native-gesture-handler';
import { useNavigation } from '#react-navigation/native';
export default function CategoryComponent() {
const containerStyle = {backgroundColor: 'white', padding: 100, margin: 10};
const [textInput, setTextInput] = useState('');
const [visible, setVisible] = useState(false);
const [categories, setCategories] = useState([])
const navigation = useNavigation();
const [dataFetch, setDataFetch] = useState(false);
useEffect(
() =>
onSnapshot(doc(db, "users", `${firebase.auth().currentUser.uid}`), (doc) => {
setCategories(doc.data().categories)
setDataFetch(true)
}
),
console.log(categories),
[]
);
useEffect(() => {
addToFirebase();
}, [categories])
const showModal = () => {
setVisible(true);
}
const hideModal = () => {
setVisible(false);
}
const categoryNavigate = (item) => {
navigation.navigate("Your Organizer tasks", {item});
}
const addCategory = (textInput) => {
setCategories((prevState) => {
return [
{name: textInput, id: Math.floor(Math.random() * 10000) + 1 },
...prevState
];
})
hideModal();
}
const addToFirebase = async() => {
if(dataFetch) {
await setDoc(doc(db, "users", `${firebase.auth().currentUser.uid}`), {
categories: categories
}, {merge: true});
}
};
const deleteItem = (item) => {
setCategories((prevState) => {
return prevState.filter(category => category.id != item.id)
})
}
const DataComponent = (item) => {
const rightSwipe = (progress, dragX) => {
const scale = dragX.interpolate({
inputRange: [-100, 0],
outputRange: [1, 0],
extrapolate: 'clamp'
});
return(
<TouchableOpacity activeOpacity={0.8} onPress={() => deleteItem(item)}>
<View>
<Animated.Text style={[styles.deleteItem, {transform: [{scale}]}]}>Delete</Animated.Text>
</View>
</TouchableOpacity>
)
}
return (
<TouchableOpacity onPress={() => categoryNavigate(item)}>
<Swipeable renderRightActions={rightSwipe}>
<View>
<Text>{item.name}</Text>
</View>
</Swipeable>
</TouchableOpacity>
)
}
return (
<View>
<Subheading>Your categories</Subheading>
<View>
<FlatList
style={styles.flatList}
keyExtractor={(item) => item.id}
data={categories}
renderItem={ ({item}) => (
<DataComponent {...item}/>
)}
/>
</View>
<View>
<Button mode="contained" uppercase={false} onPress={showModal}>
Add a category
</Button>
</View>
<Portal>
<Modal visible={visible} onDismiss={hideModal} contentContainerStyle={containerStyle}>
<Text>Name your category: </Text>
<TextInput placeholder="Enter category name" value={textInput} onChangeText={val => setTextInput(val)}/>
<Button mode="contained" uppercase={false} onPress={() => addCategory(textInput)}>
Add
</Button>
</Modal>
</Portal>
</View>
)
}
I have consol.logged the state variable categories in my useEffect and i don't understand why it shows ''undefined'' when I have initialized it as an empty array, so i would expect to see a empty array in the consol.log for the state variable categories when there is no categories in the flatlist.
If you clearly look there is no such category type key value in the object, so when you perform setCategories(doc.data().categories) it sets the categories value undefined .You can't merge or add a Doc where the field value is undefined.

ScrollView in React Native

I created a simple app, that shows a few pictures with titles. It is something like a film gallery, where you can observe all enable films. But when I try to add ScrollView element it doesn't work when I try to scroll on my emulated Android device. How can I fix it? My code looks like this:
import React, { Component } from 'react'
import { View, ScrollView, StyleSheet } from 'react-native'
import { Header, ImageCard } from './src/components/uikit'
const url = 'https://s3.eu-central-1.wasabisys.com/ghashtag/RNForKids/00-Init/data.json'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
title: 'STAR GATE',
data: []
};
}
componentDidMount = async () => {
try {
const response = await fetch(url)
const data = await response.json()
this.setState({ data })
}
catch (e) {
console.log(e)
throw e
}
}
render() {
const { title, data } = this.state
const { container } = style
return (
<View>
<Header title={title} />
<ScrollView>
<View style={container}>
{
data.map(item => {
return <ImageCard data={item} key={item.id} />
})
}
</View>
</ScrollView>
</View>
)
}
}
const style = StyleSheet.create({
container: {
marginTop: 30,
flexDirection: 'row',
flexWrap: 'wrap',
flexShrink: 2,
justifyContent: 'space-around',
marginBottom: 150
}
})
I made it with a guide, so it should work. (Youtubes author hasn't this problem on his video).
The View inside ScrollView looks problematic. Try something like:
<ScrollView contentContainerStyle={container} >
{
data.map(item => {
return <ImageCard data={item} key={item.id} />
})
}
</ScrollView>

React Native - Modal with Flatlist items

I'm making a modal that will popup when the user clicks a flatlist button or items, and there the user will see the details about the item he/she clicks. Basically, I want to pass the items of flatlist to modal.
I'm actually done with the popup of the modal, now I have to show the details like menu description and menu price. I've found a post here in stackoverflow and I follow everything in there but I am having an error regarding with an " id ", and I can't figure out how to fix it.
Here is my code
Details.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl, Dimensions, Modal, TextInput, TouchableWithoutFeedback, Keyboard
} from 'react-native';
import AddModal from '../Modal/AddModal';
var screen = Dimensions.get('window');
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress = {() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
export default class Details extends Component {
static navigationOptions = {
title: ''
};
constructor()
{
super ()
this.state = {
data: [],
showModal: false,
id: null,
}
}
fetchData = async() => {
const { params } = this.props.navigation.state;
const response_Cat = await fetch('http://192.168.254.101:3307/categories/' + params.id);
const category_Cat = await response_Cat.json();
this.setState({data: category_Cat});
};
componentDidMount() {
this.fetchData();
};
_onRefresh() {
this.setState({ refreshing: true });
this.fetchData().then(() => {
this.setState({ refreshing: false })
});
};
_onPressItem(id) {
this.setState({
modalVisible: true,
id: id
});
}
_renderItem = ({item}) => {
return (
<TouchableHighlight
id = { item.menu_desc }
onPress = { this._onPressItem(item.menu_desc) }
>
<View>
<Text>{ this.state.id }</Text>
</View>
</TouchableHighlight>
)
};
render() {
const { params } = this.props.navigation.state;
return (
<View style = { styles.container }>
<AddModal
modalVisible = { this.state.modalVisible }
setModalVisible = { (vis) => { this.setModalVisible(vis) }}
id = { this.state.id }
/>
<FlatList
data = { this.state.data }
renderItem = { this._renderItem }
keyExtractor={(item, index) => index}
/*refreshControl = {
<RefreshControl
refreshing = { this.state.refreshing }
onRefresh = { this._onRefresh.bind(this) }
/>
}*/
/>
</View>
);
}
}
const styles = StyleSheet.create({
...
})
//AppRegistry.registerComponent('Details', () => Details);
AddModal.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl, Dimensions, TextInput, Modal
} from 'react-native';
export default class AddModal extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
id: null
};
}
componentWillReceiveProps(nextProps) {
this.setState({
showModal: nextProps.showModal,
id: nextProps.id,
})
}
render() {
return (
<Modal
animationType="slide"
transparent={ true }
visible={ this.state.modalVisible }
onRequestClose={() => { this.props.setModalVisible(false) }}>
<View>
<View>
<Text>{ this.state.id }</Text>
<TouchableHighlight
onPress = {() => { this.props.setModalVisible(false) }}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
)
}
}
Just wanted to pointout an issue in your code (not related to 'id' error, id error already answer by digit). In the renderItem function, you are calling onPress = { this._onPressItem(item.menu_desc) }, it should be changed to
onPress = { () => this._onPressItem(item.menu_desc) }
I guess, you will call the onPressItem when user click on list item.
EDIT:
I have made a couple of changes to make your code working. Here are the changes.
In your AppModal.js, you are setting modal visibility in showModal: nextProps.showModal , but in the <Modal ...> you have set visible
= { this.state.modalVisible }. Also in Details.js you have written <AddModal modalVisible ...>.
First I changed showModal to modalVisible in Details.js and in AppModal.js.
Details.js
constructor()
{
super ()
this.state = {
data: [],
modalVisible: false,
id: null,
}
}
Then I changed _onPressItem(id) to _onPressItem = (id)
Made changes in renderItem as
<TouchableHighlight
id = { item.enName }
onPress = { () => this._onPressItem(item.enName) }
>
in render function I have set modal visibility as
<AddModal
...
setModalVisible = { (vis) => { this.setState({
modalVisible: vis
})
}}
...
/>
AppModal.js
Changed showModal to modalVisible
constructor(props) {
super(props);
this.state = {
modalVisible: props.modalVisible,
d: null
};
}
componentWillReceiveProps(nextProps) {
this.setState({
modalVisible: nextProps.modalVisible,
id: nextProps.id,
})
}
In the constructor, I have added modalVisible: props.modalVisible.
Hope this will help!
I guess item.menu_desc is an id of each item so it must be {item.menu_desc} not {id}. Change it like below
_renderItem = ({item}) => {
return (
<TouchableHighlight
id = { item.menu_desc }
onPress = { this._onPressItem(item.menu_desc) }
>
<View>
<Text>{ item.menu_desc }</Text>
</View>
</TouchableHighlight>
)
};

React Native Flatlist returns the wrong number of empty rows

When I run the code below, it displays 3 empty rows. It should be showing two rows each with a color and enddate and I want to use the 'Parent' as the unique key. The 'Parent' is the unique key created by Firebase when color and enddate were pushed to Firebase with '.push'.
I've tried all sorts of things to get it to display. I did get content to display when I made the 'renderItems' return 'this.state.list', but that returned 3 lines all with the same data, which is the content of the last array on the console log.
I would really appreciate some help to get this working.
Here is the code, a copy of Firebase database and the console.log. Please note that the Firebase 'goal' has been changed to 'color'.
import React, { Component } from 'react';
import { Text, FlatList, View, Image } from 'react-native';
import firebase from 'firebase';
import { Button, Card, CardSection } from '../common';
import styles from '../Styles';
class List extends Component {
static navigationOptions = {
title: 'List',
}
constructor(props) {
super(props);
this.state = {
list: [],
};
}
componentDidMount() {
const { currentUser } = firebase.auth();
const Parent = firebase.database().ref(`/users/${currentUser.uid}/Profile`);
Parent.on(('child_added'), snapshot => {
this.setState({ list: [snapshot.key, snapshot.val().color, snapshot.val().enddate] });
console.log(this.state.list);
});
}
keyExtractor = (item, index) => index;
render() {
return (
<Card>
<View style={{ flex: 1 }}>
<FlatList
data={this.state.list}
keyExtractor={this.keyExtractor}
extraData={this.state}
renderItem={({ item }) => (
<Text style={styles.listStyle}>
{ item.color }
{ item.enddate }
</Text>
)}
/>
</View>
<CardSection>
<Button
style={{
flex: 1,
flexDirection: 'row'
}}
onPress={() => this.props.navigation.navigate('NextPage', { name: 'user' })}
title="Go to next page"
>
Go to next page
</Button>
</CardSection>
</Card>
);
}
}
export { List };
This is the correct way to store the list
componentDidMount() {
const { currentUser } = firebase.auth();
const Parent = firebase.database().ref(`/users/${currentUser.uid}/Profile`);
Parent.on(('child_added'), snapshot => {
const newChild = {
key: snapshot.key,
color: snapshot.val().color,
enddate: snapshot.val().enddate
}
this.setState((prevState) => ({ list: [...prevState.list, newChild] }));
console.log(this.state.list);
});
}
and your keyExtractor
keyExtractor = (item, index) => item.key;

Categories

Resources