How to check FlatList if its null or not - reactjs

How can I check the FlatList if it's null or not and if null I will display something like No Available Booking's? I have tried the code below using short hand operator but it's not working.
{bookings == null ?
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>No Availabe Booking's Yet!</Text>
</View>
:
<FlatList
data={bookings}
renderItem={flatListItem}
refreshing={refresh}
onRefresh={refreshSummary}
keyExtractor={item => item._id}
/>
}

Instead of making checks on the data and conditionally rendering the FlatList and the empty list view, you can use the existing prop provided by the FlatList i.e. ListEmptyComponent. You can read more about the FlatList and its other props in the official documentation of the React-Native here.
A typical usage of the ListEmptyComponent could be:
import React, { PureComponent } from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
export default class BookingsList extends PureComponent {
state = {
bookings: [
// {
// _id: 1,
// title: 'I am a booking'
// }
],
refreshing: false
};
keyExtractor = (item) => String(item._id);
refreshSummary = () => {};
renderBookings = ({ item }) => (
<View style={styles.bookingCard}>
<Text style={styles.title}>{item.title}</Text>
</View>
);
renderItemSeparatorComponent = () => <View style={styles.separator} />;
//render the empty list component in case the data array for the FlatList is empty
renderListEmptyComponent = () => (
<View style={styles.emptyListContainer}>
<Text style={styles.noBookingsFound}>
No Availabe Booking's Yet!
</Text>
</View>
);
render() {
const { bookings, refreshing } = this.state;
return (
<FlatList
data={bookings}
refreshing={refreshing}
renderItem={this.renderBookings}
onRefresh={this.refreshSummary}
ListEmptyComponent={this.renderListEmptyComponent} //<==== here
ItemSeparatorComponent={this.renderItemSeparatorComponent}
contentContainerStyle={styles.list}
keyExtractor={this.keyExtractor}
/>
);
}
}
const styles = StyleSheet.create({
bookingCard: {
backgroundColor: 'white',
padding: 10,
marginTop: 2,
borderBottomWidth: 0.5
},
title: {
fontSize: 16,
fontWeight: 'bold'
},
emptyListContainer: {
alignItems: 'center',
justifyContent: 'center',
},
noBookingsFound: {
fontSize: 16,
},
separator: {
height: 15
},
list: {
paddingHorizontal: 15,
paddingBottom: 40
}
});

Would booking not be an Array for a flatlist ?
return (
{bookings !== undefined && bookings.length > 0 ?
<View>
<FlatList
data={bookings}
renderItem={flatListItem}
refreshing={refresh}
onRefresh={refreshSummary}
keyExtractor={item => item._id}
/>
</View>
:
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>No Availabe Booking's Yet!</Text>
</View>
}
);
** Edited as I think I missed your point!
You can return a conditional view in React Native as follows
return (
<View>
{state.someVar == null ?
(<ACOMPONENT />)
:
(<ADIFFCOMPONENT />)
}
</View>
);
Hopefully that's a better response.

u can use listemptycomponent
Rendered when the list is empty. Can be a React Component Class, a render function, or a rendered element.
https://reactnative.dev/docs/flatlist#listemptycomponent
<FlatList
data={bookings}
renderItem={flatListItem}
refreshing={refresh}
onRefresh={refreshSummary}
keyExtractor={item => item._id}
ListEmptyComponent={<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>No Availabe Booking's Yet!</Text>
</View>}
/>

{ bookings && Array.isArray(bookings) ? (
<FlatList
data={bookings}
renderItem={flatListItem}
refreshing={refresh}
onRefresh={refreshSummary}
keyExtractor={item => item._id}
/>
) : (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>No Availabe Booking's Yet!</Text>
</View>
)
}

Related

TextInput field retrieving undefined and not showing the value on the list screen

I am trying to add some new items on a list but when i print the list on console log it adds the item but it shows me undefined of name and description. Apparantly there is something wrong with the inputs but I cannot figure out why.
Also on the app itself the it shows that a new item is added but without data.
import React ,{useState}from 'react';
import { KeyboardAvoidingView, StyleSheet,Text,View,TextInput,TouchableOpacity,Keyboard,ScrollView } from 'react-native';
import Task from './components/task';
export default function App(){
const [recipeName,setRecipeName]=useState("");
const [descriptionItem, setDescriptionItem] = useState("");
const [items, setItems] = useState([
{ itemName: "Chicken", description: "chicken test", id: 0 }
]);
const handleAddButtonClick = () => {
const newItem = {
itemName: recipeName, // change
descriptionItem: descriptionItem,
id: items.length
};
console.log(newItem);
const newItems = [...items, newItem];
setItems((state) => {
console.log(state);
console.log(newItems);
return newItems;
});
// setRecipeName("");
// setDescriptionItem("");
// console.log(items.description);
// console.log(items.id); //...
};
return(
<View style={styles.container}>
{/* Added this scroll view to enable scrolling when list gets longer than the page */}
<ScrollView
contentContainerStyle={{
flexGrow: 1
}}
keyboardShouldPersistTaps='handled'
>
{/* Today's Tasks */}
<View style={styles.tasksWrapper}>
<Text style={styles.sectionTitle}>Today's tasks</Text>
<View style={styles.items}>
{/* This is where the tasks will go! */}
{
items.map((item, index) => {
return (
<TouchableOpacity key={index} onPress={() => completeTask(index)}>
<Text>Recipe {item.itemName} Description: {item.description}</Text>
</TouchableOpacity>
)
})
}
</View>
</View>
</ScrollView>
{/* Write a task */}
{/* Uses a keyboard avoiding view which ensures the keyboard does not cover the items on screen */}
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.writeTaskWrapper}
>
<View style={{flexDirection: 'column', flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<TextInput style={styles.input} placeholder={'Write a name'} value={recipeName} onChangeText={(text) => setRecipeName(text)} />
<TextInput style={styles.input} placeholder={'Write a date'} value={descriptionItem} onChange={(text) => setDescriptionItem(text)} />
</View>
<TouchableOpacity onPress={() => handleAddButtonClick()}>
<View style={styles.addWrapper}>
<Text style={styles.addText}>+</Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
tasksWrapper: {
paddingTop: 80,
paddingHorizontal: 20,
},
sectionTitle: {
fontSize: 24,
fontWeight: 'bold'
},
items: {
marginTop: 30,
},
writeTaskWrapper: {
position: 'absolute',
bottom: 60,
width: '100%',
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center'
},
input: {
paddingVertical: 15,
paddingHorizontal: 15,
backgroundColor: '#FFF',
borderRadius: 60,
borderColor: '#C0C0C0',
borderWidth: 1,
width: 250,
},
addWrapper: {
width: 60,
height: 60,
backgroundColor: '#FFF',
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
borderColor: '#C0C0C0',
borderWidth: 1,
},
addText: {},
});
When iterating over items in your map() function here:
items.map((item, index) => {
return (
<TouchableOpacity
key={index}
onPress={() => completeTask(index)}
>
<Text>
Recipe {item.itemName} Description: {item.description}
</Text>
</TouchableOpacity>
);
})
You are not using the correct state value. Instead of item.description, it should be item.descriptionItem.
I also advise you to move onChange events to separate methods and set the state inside them, do not use anonymous functions. So, for example, for your description, it would be something like this:
const handleDescription = (e) => {
setDescriptionItem(e.target.value);
};
And in your JSX:
<TextInput
style={styles.input}
placeholder={"Write a date"}
value={descriptionItem}
onChange={handleDescription}
/>
UPDATE:
I recreated your code in sandbox, with minor changes:
commented out the import of Task component (since I don't know what that component does)
disabled onPress event handler as I don't have access to completeTask function
changed the onChangeText for recipeName to onChange
extracted both onChange events to separated methods.
fixed initial state for items; it also had description , instead of descriptionItem
Please, feel free to check it out.

FlatList renderItem problem with return value

I am new to react native and I do not know how it works yet but I want to return cosnt Card in renderItem.I want the flat list to return the data I retrieve via axios from API. API has data for two products that it wants to throw into const Card. The problem is that I do not know what to return in renderItem. At the bottom I put the code without style to better see what I mean. I think the problem is that const Card can't see the data retrieved by AXIOS.
code:
const HomeScreen = ({navigation}) => {
const [data, setData] = useState([])
useEffect(() => {
axios.get('https://api.npoint.io/e3d714eb88eb75f37f29')
.then(({ data }) => {
console.log("defaultApp -> data", data.products)
setData(data.products)
})
.catch((error) => console.error(error))
}, []);
const Card = () => {
return (
<TouchableOpacity activeOpacity={0.8}>
<View style={style.card}>
<View style={{
flexDirection: "row",
justifyContent: 'center',
alignItems: 'center'
}}>
<Text style={{fontWeight: "bold", fontSize: 17, marginTop: 5}}>
{item.description}
</Text>
</View>
<View style={{
flexDirection: "row",
marginTop: 5,
justifyContent: 'center',
alignItems: 'center'
}}>
<Text style={{
fontSize: 18,
fontWeight: 'bold',
color: COLORS.dark_red
}}>
{item.price}
</Text>
</View>
</View>
</TouchableOpacity>
);
}
return (
<SafeAreaView
style={{
flex: 1,
paddingHorizontal: 20,
backgroundColor: COLORS.back_color,
}}>
<FlatList
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
marginTop: 10,
paddingBottom: 20
}}
data={data}
keyExtractor={({id}, index) => id}
renderItem={({item}) => {
return <Card product={item}/>; //here ?!?
}}
/>
</SafeAreaView>
);
};
export default HomeScreen;
I think you need to pass props into the Card component. Try passing item in as a prop like this:
const Card = ({ item }) => {
return (
<TouchableOpacity activeOpacity={0.8}>
...
</TouchableOpacity>
);
};
Then pass in that item prop when you render the Card component from the FlatList.
<FlatList
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
marginTop: 10,
paddingBottom: 20,
}}
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => {
return <Card item={item} />; // changed this to take in item prop
}}
/>;

Delete multiple items using state in FlatList. React Native

I am trying to make a to do list using React Native. How can I delete multiple items in FlatList all the items that has the state of completed: true with a TouchableOpacity(acting like a button). I do not know what methods I should put in function deleteCompleteTodo()
import React, {useState} from 'react';
import { Text, SafeAreaView, StatusBar, FlatList, View, TouchableOpacity,Button, Alert } from 'react-native';
import TodoInput from "./TodoInput";
import TodoItem from "./TodoItem";
const App = () => {
const [todoItems, setTodoItems] = useState([{text: "Buy groceries", completed: true}, {text: "Make blogpost", completed: false}]);
// Add a new item to the state
function addTodoItem(_text) {
setTodoItems([...todoItems, {text:_text, completed: false}]);
}
// Delete an item from state by index
function deleteTodoItem(_index){
let tempArr = [...todoItems];
tempArr.splice(_index, 1);
setTodoItems(tempArr)
}
// Function to set completed to true by index.
function completeTodoItem(_index){
let tempArr = [...todoItems];
if(tempArr[_index].completed){
tempArr[_index].completed = false
}
else{
tempArr[_index].completed = true
}
setTodoItems(tempArr)
}
// Function to delete all completed task
function deleteCompleteTodo(){
let tempArr = [...todoItems];
var i=0;
tempArr.map()
}
// Render
return (
<>
<View style={{flex: 1}}>
<SafeAreaView style={{justifyContent: 'flex-start', flex: 1, backgroundColor: '#dfdfdf', padding: 14, paddingTop: 35}}>
<StatusBar barStyle={"light-content"} backgroundColor={"#212121"}/>
<View style={{flexDirection: 'row', height: 45, justifyContent: 'space-between', marginBottom: 10, borderRadius: 10, backgroundColor: '#d4d1c9'}}>
<View style={{paddingHorizontal: 10, paddingVertical: 5}}>
<Text style={{fontSize: 36, fontWeight: 'bold'}}>Todo</Text>
</View>
{/*Button*/}
<View style={{paddingHorizontal: 10, paddingVertical: 5}}>
{/* <Text style={{fontSize: 36, fontWeight: 'bold'}}>D</Text> */}
<TouchableOpacity
style={{width:50, paddingVertical:8 , backgroundColor: '#ff0000', justifyContent: 'center', alignItems: 'center', borderRadius: 100}}
onPress={() => deleteCompleteTodo()}>
<Text style={{color: '#fafafa', fontWeight: 'bold'}}>Delete</Text>
</TouchableOpacity>
</View>
</View>
<FlatList
data={todoItems}
keyExtractor={(item, index) => index.toString()}
renderItem={({item, index}) => {
return (
<TodoItem
item={item}
deleteFunction={() => deleteTodoItem(index)}
completeFunction={() => completeTodoItem(index)}
/>
)
}}
/>
<TodoInput onPress={addTodoItem} />
</SafeAreaView>
</View>
</>
);
};
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
You can use filter to delete multy items:
deleteCompleteTodo = () => {
setTodoItems(preState => preState.filter(item => !item.completed))
}

React native custom view

I am developing an app where the user adds item name, description, quantity and image url and it gets stored in AsyncStorage. I have made it ready and it looks like this:
Now i am trying to fetch it from Asyncstorage and i Get a 2D array. Here is the code:
myA1 = await AsyncStorage.getItem('key1');
var ee=JSON.parse(myA1); //ee is 2D array
It looks like this
[[imgurl1 itemname1, desc1, quantity1],
[imgurl2 itemname2, desc2, quantity3],
[imgurl3 itemname3, desc2, quantity3],
[imgurl4 itemname4, desc2, quantity3]]
How can I acheive this??
I am beginner for react native
I want to display it as follows
:
You van use FlatList for rendering a list of data. It has a renderItem prop that you can pass a view to render each row of data like that. Put your data in an state (data in this code). Here is an example:
makeContentItem(item) {
return (
<TouchableOpacity
onPress={() => {
//Do sth when clicking on a row
}}>
<View style={{ width: '90%', height: 140, marginBottom: 5, borderRadius: 2, backgroundColor: 'white' }}>
<View style={{ flex: 1, flexDirection: 'row' }}>
<Image style={{ width: 40, height: 40 }} source={require(item.imgurl)} />
<View>
<Text>{item.itemname}</Text>
<Text>{item.desc}</Text>
<Text>{item.quantity}</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
}
render() {
return (
<FlatList
data={this.state.data}
renderItem={({ item, index }) => {
return this.makeContentItem(item)
}
/>
)
}
You can change the style to achieve what you want. also you can take a look at FlatList
I hope it will help
renderEditAndClose() {
return(
<View style={{flex:1, flexDirection: "row", justifyContent: "flex-end"}}>
{this.renderEditImage()}
{this.renderCloseImage()}
</View>
);
}
renderImageAndItemData(item: Object) {
return(
<View style={{flex:1, flexDirection:"row"}}>
{this.renderItemImage()}
{this.renderItemData(item)}
</View>
);
}
renderItemImage(width: number, height: number, url: string) {
return (
<Image style={{ width: width, height: height }} source={{uri: url}} />
);
}
renderItemData(item: Object) {
return(
<View>
<View style={{flex: 1, flexDirection: "row", justifyContent: "space-around"}}>
<Text>{item.name}</Text>
<Text>{item.quantity}</Text>
</View>
<Text>{item.description}</Text>
</View>
);
}
renderRow(item: Object) {
return() {
<View>
{this.renderEditAndClose()}
{this.renderImageAndItemData(item)}
</View>
}
}
render() {
return (
<FlatList data={ee}
renderItem={(item) => this.renderRow(item)} />
);
}

how to add keys in this project

im using react o nexpo xde and when i run the project i get a warning because my list doesnt hae keys, i want to know where and how to assing them, this is my code
import React, { Component } from 'react';
import { StyleSheet, Text, View,AppRegistry,Image,ActivityIndicator, FlatList,Navigator,TouchableHighlight, } from 'react-native';
import { StackNavigator } from 'react-navigation';
class Lista extends Component {
static navigationOptions = {
title: 'Lista',
}
constructor(props) {
super(props);
this.state = {
data:[]
};
}
load = async ()=>{
try{
let resp = await fetch('https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=fd829ddc49214efb935920463668608d')
let json = await resp.json()
this.setState({data:json.articles})
} catch (err) { console.log(err) }
}
componentDidMount(){this.load()}
render() {
return (
<View style={{ flex: 1}}>
<View style={{ flex:1,backgroundColor:'gray'}}>
<FlatList
data={this.state.data}
renderItem={({item}) => (
<TouchableHighlight onPress={() => this.props.navigation.navigate('Details', {item})}>
<View style={{ height:100,margin:15,backgroundColor:'skyblue', padding: 10, flexDirection: 'row'}}>
{item.urlToImage !== null &&
<Image source={{uri:item.urlToImage}} style={{width: 90, height: 80 }}/>
}
<View style={{ flex: 1 }}>
<Text style={{ textAlign: 'center',fontWeight: 'bold', fontSize: 18, color: 'white', flex:1, margin:10}}>{item.title}</Text>
<Text style={{ textAlign: 'right',fontWeight: 'bold', fontSize: 11, color: 'white'}}>{item.publishedAt}</Text>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
}
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { item } = navigation.state;
return {
title: item ? item.date : 'Details Screen',
}
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Image source={{uri:this.props.navigation.state.params.item.urlToImage}} style={{width: 90, height: 80 }}/>
<Text>{this.props.navigation.state.params.item.title}</Text>
<Text>{this.props.navigation.state.params.item.publishedAt}</Text>
</View>
);
}
}
const RootStack = StackNavigator(
{
Lista: {
screen: Lista,
},
Details: {
screen: DetailsScreen,
},
},
{
initialRouteName: 'Lista',
}
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
i know it has to be something like, key={i} bu i hae tried in some ways and it doesnt work, im just learning react by myself so im a little confused here
ty so much
In your case you need to set up key to each child of <FlatList /> component. By react native docs recomended to use keyExtractor method defined in your component.
keyExtractor = (item, index) => index
render() {
return (
<View style={{ flex: 1}}>
<View style={{ flex:1,backgroundColor:'gray'}}>
<FlatList
data={this.state.data}
keyExtractor={this.keyExtractor}
renderItem={({item}) => (
<TouchableHighlight onPress={() => this.props.navigation.navigate('Details', {item})}>
<View style={{ height:100,margin:15,backgroundColor:'skyblue', padding: 10, flexDirection: 'row'}}>
{item.urlToImage !== null &&
<Image source={{uri:item.urlToImage}} style={{width: 90, height: 80 }}/>
}
<View style={{ flex: 1 }}>
<Text style= {{ textAlign: 'center',fontWeight: 'bold', fontSize: 18, color: 'white', flex:1, margin:10}}>{item.title}</Text>
<Text style= {{ textAlign: 'right',fontWeight: 'bold', fontSize: 11, color: 'white'}}>{item.publishedAt}</Text>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
I set just index of element as key, but you can set as you wont, but make sure it is unique. But using indexes is bad practice, it is not safe.

Resources