react native navigation refresh component problem - react-native

I'm in category page and when i press any of them, it navigates me to the that categories product list. so far so good. when i go back and press another category i get previous categories product list.
there is my some of code
this is how i navigate to product list
render() {
const {navigation} = this.props.navigation;
const categories = category.map((item, index) => {
return (
<TouchableOpacity
key={index}
styles={styles.category}
onPress={() =>
navigation.navigate('ProductList', {
categoryName: item.Menu,
})
}>
<Text> {item.Menu} </Text>
</TouchableOpacity>
);
});
return (
<View style={styles.container}>
{this.state.isData ? (
<View style={styles.container}>
<Text style={styles.title}>Category</Text>
{categories}
</View>
) : (
<ActivityIndicator size="large" color="#0B970B" />
)}
</View>
);
}
}
and this is where i go, i can get navigation props ext. but i cant find where the problem is
import React,{useState,useEffect} from 'react';
import {
View,
ScrollView,
Text,
Image,
StyleSheet,
Dimensions,
ActivityIndicator,
} from 'react-native';
const List = ({navigation}) => {
const [isData, setIsData] = useState(false);
useEffect(() => {
getData();
return null;
}, []);
const getData = async () => {
if (navigation?.route?.params?.categoryName) {
categoryName = navigation.route.params.categoryName;
fetch(global.apiPost + global.token, requestOptions)
.then((response) => response.json())
.then((result) => {
result.forEach((element) => {
if (element.Menu === categoryName) {
products.push(element);
}
});
setIsData(true);
console.log(products, 'products');
console.log(productsByAccessory, 'productsByAccessory');
console.log(productsByTravel, 'productsByTravel');
console.log(productsByBag, 'productsByBag');
})
.catch((error) => console.log('error', error));
}
};
return (
<View style={{flex: 1}}>
<Text style={styles.title}>{categoryName}</Text>
{isData ? (
<View style={{flex: 1}}>
<View style={styles.itemFounds}>
<Text>{data.length + ' item founds'}</Text>
</View>
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
<Text>
{productsByAccessory.length} / {productsByTravel.length} /{' '}
{productsByBag.length} / {products.length} asd
</Text>
</View>
</View>
) : (
<ActivityIndicator size="large" color="#0B970B" />
)}
</View>
);
}
export default List

Change your render method
const { navigation } = this.props; // Here was the error
const categories = category.map((item, index) => {
return (
<TouchableOpacity
key={index}
styles={styles.category}
onPress={() =>
navigation.navigate("ProductList", {
categoryName: item.Menu,
})
}
>
<Text> {item.Menu} </Text>
</TouchableOpacity>
);
});
render() {
return (
<View style={styles.container}>
{this.state.isData ? (
<View style={styles.container}>
<Text style={styles.title}>Category</Text>
{categories}
</View>
) : (
<ActivityIndicator size="large" color="#0B970B" />
)}
</View>
);
}
}
render method should have the return statement only. Don't perform any operations inside the render method. Now it should work.

Related

React Native inputText with Flatlist

I'm new to react-native. This component below should render comments posted by users, I would like to add an inputText component from react-native to allow users to post a comment, but don't know where I should place it within the code below.
import React, { useState, useEffect } from 'react';
import { useNavigation } from "#react-navigation/native";
import Icon from 'react-native-vector-icons/AntDesign';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
ScrollView,
FlatList,
Button,
TextInput
} from 'react-native';
import parseDate from "../utils/parseDate";
import * as API from "../api/api"
export default function CommentList({ ride }) {
const [text, setText] = React.useState("");
const [commentsData, setComments] = useState([]);
const navigation = useNavigation();
useEffect(() => {
API.getCommentsByRideId(ride.ride_id).then((comments) => {
setComments(comments)
})
}, [ride.ride_id])
deleteComment = (comment_id) => {
// useEffect(() => {
API.deleteCommentsByCommentId(comment_id).then(() => {
const updatedComments = list.filter((item) => item.comment_id !== comment_id);
setComments(updatedComments)
})
// }, [comment_id])
}
//deletes on refresh only
addComment = (newComment, ride_id) => {
API.postCommentByRideId(newComment, ride_id).then(() => {
setComments(newComment)
})
}
return (
<FlatList
style={styles.root}
data={commentsData}
ItemSeparatorComponent={() => {
return (
<View style={styles.separator} />
)
}}
keyExtractor={(item) => {
return item.author;
}}
renderItem={(item) => {
const comment = item.item;
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => navigation.navigate("UserProfile", { username: item.author })}>
{/* <Image style={styles.image} source={{ uri: comment.avatar_url }} /> */}
</TouchableOpacity>
<View style={styles.content}>
<View style={styles.contentHeader}>
<Text style={styles.name}>{comment.author}</Text>
<Text style={styles.time}>
{parseDate(comment.created_at)}
{comment.votes}
</Text>
</View>
<Text rkType='primary3 mediumLine'>{comment.body}</Text>
{/* <Text style={styles.time}> Likes: {comment.votes}</Text> */}
<TouchableOpacity onPress={() => deleteComment(comment.comment_id)}>
<Icon name="delete" size={20} color="#e33057" />
</TouchableOpacity>
</View>
</View>
);
}} />
);
}
This is the inputText I would like to add to allow users to post a comment.
<TextInput
value={text}
placeholder="write..."
onChangeText={text => setText(text)}
onSubmitEditing={() => addcomment(text, ride.ride_id)}
/>
if you want to add it at fixed position in bottom of screen you may do this
<View style={{flex : 1}}>
<Flatlist
contentContainerStyle={{paddingBottom: 50}}
.../>
<View style={{position : 'absolute', bottom : 0, width : '100%', height : 50}}>
//you input here
</View>
</View>
or if you want to add it last item of flatlist you may use ListFooterComponent
<FlatList
ListFooterComponent={<Input/>}
.../>
</FlatList>

fetch API call in react native is not working when I load the screeen

I have made an App in react native. My app makes API calls to my webserver and then Displays information based on that. The problem Is when I first load this screen... I get the loading screen and the information is display in the way it is supposed to but when I leave the screen and then comeback to the screen, it shows nothing and my array containing the items is empty, hence I think I am having problems with the API call when I leave the screen and then come back.
I am using React navigation 5 in My App.
export default function ({ navigation }) {
const [openQueries, setOpenQueries] = useState([]);
const [isLoading, seIsLoading] = useState(true);
const open_queries = [];
function getOpenQueries() {
var retrieveData = async () => {
try {
var value = await AsyncStorage.getItem("user");
var data = JSON.parse(value);
return data.user._id;
} catch (error) {
alert(error);
}
};
retrieveData().then((user) => {
fetch(URL + "/api/contact/open_queries", {
method: "POST",
body: "user=" + user + "&status=open",
headers: { "Content-type": "application/x-www-form-urlencoded" },
})
.then((response) => {
return response.json();
})
.then((responseJson) => {
if (responseJson.error === null) {
setOpenQueries(responseJson.open_queries);
seIsLoading(false);
}
});
});
}
getOpenQueries();
openQueries.forEach((query) => {
open_queries.push(
<TouchableOpacity
onPress={() =>
navigation.navigate("Chat", {
id: query._id,
title: query.title,
query: query,
showInput: true,
})
}
>
<View style={styles.inboxItem}>
<Text style={styles.inboxTitle}>{query.title}</Text>
<Text style={styles.inboxSubtext}>
{query.chats[query.chats.length - 1].chat}
</Text>
<View style={styles.lineBreak}></View>
</View>
</TouchableOpacity>
);
});
return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>Contacts</Text>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate("NewQuery")}
>
<Text style={styles.text}>Start a new query</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate("ClosedQueries")}>
<View style={styles.button}>
<Text style={styles.text}>Closed Queries</Text>
</View>
</TouchableOpacity>
<Text style={styles.subTitle}>Open Queries</Text>
{isLoading ? (
<View style={styles.loader}>
<Code />
</View>
) : (
<ScrollView style={{ paddingTop: 10 }}>
{openQueries.length > 0 ? (
open_queries
) : (
<Text style={styles.noQuery}>No Open Queries found</Text>
)}
</ScrollView>
)}
<ScrollView></ScrollView>
<BottomNavigation navigation={navigation} active={"contact"} />
</SafeAreaView>
);
}
Try this way
export default function ({ navigation }) {
const [openQueries, setOpenQueries] = useState([]);
const [isLoading, seIsLoading] = useState(true);
const [open_queries_views, setOpenQueriesViews] = useState([]);
function getOpenQueries() {
....
}
// Similar to componentDidMount
useEffect(() => {
getOpenQueries();
});
function renderViews(){
const open_queries = [];
openQueries.forEach((query) => {
open_queries.push(
<TouchableOpacity> ... </TouchableOpacity>
);
});
setOpenQueriesViews(open_queries); // set state here to auto reflect on view
}
return (
<SafeAreaView style={styles.container}>
....
<ScrollView style={{ paddingTop: 10 }}>
{open_queries_views.length > 0 ? (
open_queries_views
) : (
<Text style={styles.noQuery}>No Open Queries found</Text>
)}
</ScrollView>
.....
</SafeAreaView>
);
}

Call function on another file JS React Native

I have a Parent Class and Child Class but however i can't call a function on Parent Class from Child Class
It just for close the Modal and send a few data from Sorting on my modal. Sorry im a newbie on RN
On OrderScreen i want to separate a modal and screen, so i call modal on another file JS, then on ModalSort.js i want to call back that function has been on his Parents or Order.screen.js
so many way i try but that modal still can't close, if i put onBackdropPress={() => ()} the modal can be close but no respon that i got
Order.screen.js (a.k.a Parents.js)
class OrderScreen extends Component {
constructor(props) {
super(props);
this.state = {
visibleModal: null,
};
};
exit = () => this.setState({ visibleModal: false });
_applySort = () => {
this.setState({ visibleModal: false });
this.onRefresh();
};
pressSort = () => this.setState({ visibleModal: 4 });
render() {
return (
<View style={styles.containerTop}>
<Modal isVisible={this.state.visibleModal === 5} style={styles.bottomModal}>
{this._renderModal()}
</Modal>
<Modal isVisible={this.state.visibleModal === 4}
style={styles.bottomModal} onBackdropPress={() => {this.toggleModal();}}>
{this._renderModalSort()}
</Modal>
<Modal isVisible={this.state.visibleModal === 3} style={styles.bottomModal}>
{this._renderModalFilter()}
</Modal>
<Modal isVisible={this.state.visibleModal === 2} style={styles.bottomModal}>
{this._renderModalEmail()}
</Modal>
<NavigationEvents
onWillFocus={this.willFocusAction} />
<GeneralStatusBarColor backgroundColor="#FFF" barStyle="light-content" />
</View>
)
};
_renderModalSort = () => {
return (
<ModalSort
exit={() => {
this.exit.bind(this);
}}
/>
)
};
const mapStateToProps = ({ authOrder }) => {
const { orderSummary, error, loading, loadingSummary, loadingEmail, typeOfLocation, openNext, openList, closedList, closedNext } = authOrder;
return { orderSummary, error, loading, loadingSummary, loadingEmail, typeOfLocation, openNext, openList, closedList, closedNext };
};
export default connect(mapStateToProps, { getOrderSummary, getOpenOrderList, getClosedOrderList, sendEmailCsvAllOrder, logoutSession })(OrderScreen);
ModalSort.js (a.k.a Child.js)
class ModalSort extends Component {
constructor(props) {
super(props);
this.state = {
visibleModal: null,
}
};
sorter = (isi) => this.setState({ sorted: isi });
_applySort = () => {
this.setState({ visibleModal: false });
// this.onRefresh();
};
render() {
return(
<View style={styles.modalContentSort}>
<View style={styles.modalCenter}>
<View style={styles.headerModel}>
<View style={styles.headerBack}>
<TouchableOpacity onPress={()=>{this.props.exit()}}>
{/* <NavigationEvents onWillFocus={this.willFocusAction} /> */}
<Image style={styles.logoClose} source={require('../../assets/icons/iconClose.png')} />
</TouchableOpacity>
</View>
<View style={styles.headerSort}>
<Text style={styles.textFilter}>Sort by</Text>
</View>
</View>
<Text style={styles.textFilter}>SO Number</Text>
<View style={styles.headerModel}>
<View style={styles.headerFilterItem}>
<TouchableOpacity onPress={() => this.sorter(1)}>
<Text style={this.state.sorted == 1 ? styles.headerBorderItemActive : styles.headerBorderItem}>
<Image style={styles.imageSort} source={require('../../assets/icons/iconNumberAscending.png')} />Ascending</Text>
</TouchableOpacity>
</View>
<View style={styles.headerFilterItem}>
<TouchableOpacity onPress={() => this.sorter(2)}>
<Text style={this.state.sorted == 2 ? styles.headerBorderItemActive : styles.headerBorderItem}>
<Image style={styles.imageSort} source={require('../../assets/icons/iconNumberDescending.png')} />Descending</Text>
</TouchableOpacity>
</View>
</View>
<Text style={styles.textFilter}>PO Customer</Text>
<View style={styles.headerModel}>
<View style={styles.headerFilterItem}>
<TouchableOpacity onPress={() => this.sorter(3)}>
<Text style={this.state.sorted == 3 ? styles.headerBorderItemActive : styles.headerBorderItem}>
<Image style={styles.imageSort} source={require('../../assets/icons/iconNumberAscending.png')} />Ascending</Text>
</TouchableOpacity>
</View>
<View style={styles.headerFilterItem}>
<TouchableOpacity onPress={() => this.sorter(4)}>
<Text style={this.state.sorted == 4 ? styles.headerBorderItemActive : styles.headerBorderItem}>
<Image style={styles.imageSort} source={require('../../assets/icons/iconNumberDescending.png')} />Descending</Text>
</TouchableOpacity>
</View>
</View>
<Text style={styles.textFilter}>SO Date</Text>
<View style={styles.headerModel}>
<TouchableOpacity onPress={() => this.sorter(6)}>
<View style={styles.headerFilterItem}>
<Text style={this.state.sorted == 6 ? styles.headerBorderItemActive : styles.headerBorderItem}>Newest</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.sorter(5)}>
<View style={styles.headerFilterItem}>
<Text style={this.state.sorted == 5 ? styles.headerBorderItemActive : styles.headerBorderItem}>Oldest</Text>
</View>
</TouchableOpacity>
</View>
<Text style={styles.textFilter}>ETA</Text>
<View style={styles.headerModel}>
<TouchableOpacity onPress={() => this.sorter(8)}>
<View style={styles.headerFilterItem}>
<Text style={this.state.sorted == 8 ? styles.headerBorderItemActive : styles.headerBorderItem}>Newest</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.sorter(7)}>
<View style={styles.headerFilterItem}>
<Text style={this.state.sorted == 7 ? styles.headerBorderItemActive : styles.headerBorderItem}>Oldest</Text>
</View>
</TouchableOpacity>
</View>
<TouchableHighlight style={styles.buttonSort} onPress={this._applySort.bind(this)} >
<Text style={styles.textApply}>Apply</Text>
</TouchableHighlight>
</View>
</View>
)
};
}
export default ModalSort;
Close modal in Parent component from Child component:
Your Order.screen.js has a mistake that make your program wouldn't run properly. When you use this.exit.bind(this);, it will return a callback, not a function. So, when you call this.props.exit() in ModalSort.js, it will call exit that actually shows nothing. To resolve this, you have 2 ways:
Order.screen.js
_renderModalSort = () => {
return (
<ModalSort
exit={this.exit.bind(this)}
/>
)
};
or
_renderModalSort = () => {
return (
<ModalSort
exit={() => {
this.exit();
}}
/>
)
};
Send data from sorting modal:
Since you're using Redux, I suggest you create 2 actions. First action is to save your data to your state tree. Second one is to get those data. If you're not good at Redux, or you don't want to use it, you can try these step:
Initialize a variable to hold your data in Parent:
class OrderScreen extends Component {
constructor(props) {
super(props);
this.state = {
visibleModal: null,
};
this.data = null; // Your data goes here.
/*
You can store your data in state if you want to re-render when updating your data.
this.state = {
visibleModal: null,
data: null
}
*/
}
}
Create a function that save your data in Parent:
saveData(data) {
this.data = data;
}
Pass that function to Child:
_renderModalSort = () => {
return (
<ModalSort
exit={() => {
this.exit();
}}
saveData={(data) => {
this.saveData(data);
}}
/>
)
};
Lastly, you can call it from Child:
class ModalSort extends Component {
sorting() {
data = null; // Your data will be stored in this variable
// You sorting function goes here
this.props.saveData(data); // Save your data
}
}
In case you have other works to do with saved data, you can modify the saveData(data) function in Parent.
Hope this will help you!

React Native Flatlist rendering items

I am not able to show my flatlist and I am not sure whether my coding is correct. There is no output if when I run this. It will only show a white screen. My data is correct which is this.props.section.songs. I want to show the title and artist in my text but I am unable to do that.
export default class SongList extends Component
{
renderSongsList() {
return(
<View>
<FlatList
data = {this.props.section.songs}
renderItem={(song, sectionId, rowId) => (
<TouchableOpacity onPress={ () => Actions.Player({songIndex: parseInt( rowId ),songs: this.props.section.songs, section: this.props.section }) }>
<View key={song} style={ styles.song }>
<Text style={styles.itemTitle}>
{ song.title}
</Text >
<Text style={styles.itemArtist}>
{ song.artist }
</Text>
</View>
</TouchableOpacity>
)}
/>
</View>
);
}
render()
{
return (
<View>
{ this.renderSongsList() }
</View>
);}}
export default class SongList extends Component
{
renderSongsList() {
return(
<View>
<FlatList
data = {this.props.section.songs}
// You have to cross check the values you receive here. Better is to receive a array item
//here and pass to the render props
// Or try {song, sectionId, rowId} this in place of (song, sectionId, rowId) see below
renderItem={({song, sectionId, rowId}) => (
<TouchableOpacity onPress={ () => Actions.Player({songIndex: parseInt( rowId ),songs: this.props.section.songs, section: this.props.section }) }>
<View key={song} style={ styles.song }>
<Text style={styles.itemTitle}>
{ song.title}
</Text >
<Text style={styles.itemArtist}>
{ song.artist }
</Text>
</View>
</TouchableOpacity>
)}
/>
</View>
);
}
render()
{
return (
<View>
{ this.renderSongsList() }
</View>
);}}
export default class SongList extends Component
{
renderItems(item){
// Here you can access all items of your json by item.property
// Like your JSON is { id: '1', title: 'Better Now', artist: 'Post Malone', }
// You can access these values as item.id, item.title etc
}
renderSongsList() {
return(
<View>
<FlatList
data = {this.props.section.songs}
renderItem={(item) => this.renderItems(item)}
/>
</View>
);
}
render()
{
return (
<View>
{ this.renderSongsList() }
</View>
);}}

AsyncStorage mapping not working

I have code
AsyncStorage.getItem("Friends").then((value) => {
this.setState({"Friends": value});
}).done();
I am trying to show in list using
render() {
return ({
this.state.Friends.map((o,i) => {
<View key={i} style={styles.row}>
<View>
<Text style={styles.app_type_name}>{o.name}</Text>
</View>
</View>
})
})
}
I am getting
error evaluating object 'this.state.Friends'
You render method should looks like :
render() {
const {Friends} = this.state;
return (
<div>
{
Friends && Friends.map((o,i) =>
<View key={i} style={styles.row}>
<View><Text style={styles.app_type_name}>{o.name}</Text></View>
</View>
)
}
</div>
);
}