Add items to FlatList dynamically in React Native - javascript

I have a FlatList with two items. I need to append this list with another elements. When the user clicks on the button, the data from the text inputs should appear in the end of the FlatList. So, I've tried to push data object to the end of the list's array, but new item replaces the last one.
import React, { useState } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
export default function HomeScreen() {
var initialElements = [
{ id : "0", text : "Object 1"},
{ id : "1", text : "Object 2"},
]
const [exampleState, setExampleState] = useState(initialElements);
const [idx, incr] = useState(2);
const addElement = () => {
var newArray = [...initialElements , {id : toString(idx), text: "Object " + (idx+1) }];
initialElements.push({id : toString(idx), text: "Object " + (idx+1) });
incr(idx + 1);
setExampleState(newArray);
}
return (
<View style={styles.container}>
<FlatList
keyExtractor = {item => item.id}
data={exampleState}
renderItem = {item => (<Text>{item.item.text}</Text>)} />
<Button
title="Add element"
onPress={addElement} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
width: '100%',
borderWidth: 1
},
});

import React, { useState } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
export default function HomeScreen() {
var initialElements = [
{ id : "0", text : "Object 1"},
{ id : "1", text : "Object 2"},
]
const [exampleState, setExampleState] = useState(initialElements)
const addElement = () => {
var newArray = [...initialElements , {id : "2", text: "Object 3"}];
setExampleState(newArray);
}
return (
<View style={styles.container}>
<FlatList
keyExtractor = {item => item.id}
data={exampleState}
renderItem = {item => (<Text>{item.item.text}</Text>)} />
<Button
title="Add element"
onPress={addElement} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
width: '100%',
borderWidth: 1
},
});
You are just changing the listElements array. This will NOT trigger the re rendering of the component and hence the flat list will be unchanged.
Create a state variable in the component and store your data in that so that any modification results in re rendering.

I fixed the problem of replacing elements by changing array into a state variable.
import React, { useState } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
export default function HomeScreen() {
const [initialElements, changeEl] = useState([
{ id : "0", text : "Object 1"},
{ id : "1", text : "Object 2"},
]);
const [exampleState, setExampleState] = useState(initialElements);
const [idx, incr] = useState(2);
const addElement = () => {
var newArray = [...initialElements , {id : idx, text: "Object " + (idx+1) }];
incr(idx + 1);
console.log(initialElements.length);
setExampleState(newArray);
changeEl(newArray);
}
return (
<View style={styles.container}>
<FlatList
keyExtractor = {item => item.id}
data={exampleState}
renderItem = {item => (<Text>{item.item.text}</Text>)} />
<Button
title="Add element"
onPress={addElement} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
width: '100%',
borderWidth: 1
},
});

i fixed it by defining the array outside the export function
import React, { useState } from 'react'
import { StyleSheet, View, TextInput, TouchableOpacity, Text, FlatList } from 'react-native'
let tipArray = [
{key: '1', tip: 20},
{key: '2', tip: 12}
]
const screen = function tipInputScreen( {navigation} ) {
const [ tip, setTip ] = useState('')
const addTip = ()=>{
if(tip == "")return
tipArray.push({key: (tipArray.length + 1).toString(), tip})
setTip('')
}
const logInput = (input)=>{
setTip(input)
}
const renderTip = ({ item }) => {
return(
<TouchableOpacity style={styles.listItem}>
<Text style={styles.buttonText}>{`${item.tip} $`}</Text>
</TouchableOpacity>)
}
return (
<View
style={styles.background}>
<TextInput
style={styles.input}
keyboardType={'number-pad'}
keyboardAppearance={'dark'}
onChangeText={logInput}
value={tip}
/>
<TouchableOpacity
style={styles.redButton}
onPress={addTip}>
<Text style={styles.buttonText}>Add Tip</Text>
</TouchableOpacity>
<FlatList
data={tipArray}
renderItem={renderTip}
style={styles.flatList}
/>
</View>
)
}
const styles = StyleSheet.create({
background: {
backgroundColor: 'grey',
paddingTop: Platform.OS === "android" ? 25:0,
width: '100%',
height: '100%',
alignItems: 'center'
},
input: {
marginTop:40,
color:'white',
fontSize:30,
backgroundColor: "#2e2a2a",
height: 50,
width: '90%',
textDecorationColor: "white",
borderColor: 'black',
borderWidth: 2
},
flatList:{
width: "100%"
},
listItem: {
width: "90%",
height: 50,
backgroundColor: "#2e2e2e",
borderRadius: 25,
marginVertical: 4,
marginHorizontal: "5%",
justifyContent: "center"
},
listItemTitle: {
color: "white",
textAlign: "center",
fontSize: 18
},
redButton: {
justifyContent: "center",
width: "90%",
height: 50,
backgroundColor: "red",
borderRadius: 25,
marginHorizontal: 20,
marginVertical: 10
},
buttonText: {
color: "white",
textAlign: "center",
fontSize: 18
}
})
export default screen;
this was part of an larger app, but it should do the trick, I hope it helps

Related

ReferenceError: Can't find variable: itemData

I am developing a Meals App refering to a React Native - The Practical Guide [2023]
course in Udemy. While using a native route prop i am facin with the mentioned error i.e can't find itemData
Can some help me to figure out where this code is going wrong.
CategoriesScreen.js
import { FlatList, StyleSheet } from "react-native";
import { CATEGORIES } from "../data/dummy-data";
import CategoryGridTile from "../components/CategoryGridTile";
function CategoriesScreen({ navigation }) {
function pressHandler() {
navigation.navigate("Meals Overview", { categoryId: itemData.item.id, });
}
function renderCategoryItem(itemData) {
return (
<CategoryGridTile
title={itemData.item.title}
color={itemData.item.color}
onPress={pressHandler}
/>
);
}
return (
<FlatList
data={CATEGORIES}
keyExtractor={(item) => item.id}
renderItem={renderCategoryItem}
numColumns={2}
/>
);
}
export default CategoriesScreen;
MealsOverviewScreen
import { View,Text,StyleSheet } from "react-native";
import {MEALS} from "../data/dummy-data"
function MealsOverviewScreen({route}){
const catId=route.params.categoryId;
return(
<View style={styles.container}>
<Text>Meals Overview Screen - {catId}</Text>
</View>
)
}
export default MealsOverviewScreen;
const styles=StyleSheet.create(
{
container:{
flex:1,
padding:16,
}
}
)
CategoryGridTile.js
import { Pressable, View, Text, StyleSheet, Platform } from "react-native";
function CategoryGridTile({ title, color,onPress}) {
return (
<View style={styles.gridItem}>
<Pressable
style={({ pressed }) => [styles.buttonStyle,pressed?styles.buttonPressed:null,]}
android_ripple={{ color: "#ccc" }}
onPress={onPress}
>
<View style={[styles.innerContainer,{backgroundColor:color }]}>
<Text style={styles.title}>{title}</Text>
</View>
</Pressable>
</View>
);
}
export default CategoryGridTile;
const styles = StyleSheet.create({
gridItem: {
flex: 1,
margin: 16,
height: 150,
borderRadius: 8,
elevation: 4,
backgroundColor: "white",
shadowColor: "black",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 8,
overflow: Platform.OS == "android" ? "hidden" : "visible",
},
buttonPressed: {
opacity: 0.25,
},
buttonStyle: {
flex: 1,
},
innerContainer: {
flex: 1,
padding: 16,
borderRadius:8,
alignItems: "center",
justifyContent: "center",
},
title: {
fontSize: 18,
fontWeight: "bold",
},
});
Issue is in pressHandler function . There is no itemData variable declared and initialised in function but still you are trying to use it ..
You can change code in CategoriesScreen function created in CategoriesScreen.js as mentioned below
From
function renderCategoryItem(itemData) {
return (
<CategoryGridTile
title={itemData.item.title}
color={itemData.item.color}
onPress={pressHandler}
/>
);
}
To
function renderCategoryItem(itemData) {
return (
<CategoryGridTile
title={itemData.item.title}
color={itemData.item.color}
onPress={()=>{
pressHandler(itemData)
}}
/>
);
}
From
function pressHandler() {
navigation.navigate("Meals Overview", { categoryId: itemData.item.id, });
}
To
function pressHandler(itemData) {
navigation.navigate("Meals Overview", { categoryId: itemData.item.id, });
}

How to set Switch component separately for each item that comes From API in React native

I have an API and I need to set the switch button separately for each
item. I read different answers but didn't solve my problem as I tried
all of the answers.
const results = [
{
Id: "IySO9wUrt8",
Name: "Los Stand",
Category: "Mexican",
Status: true,
},
{
Id: "IySO9wUrt8",
Name: "Los Stand 2",
Category: "Burger",
Status: true,
},
{
Id: "IySO9wUrt8",
Name: "Los Stand 3",
Category: "BBq",
Status: true,
},
];
in the above code I need to set the Status in switch . If status is
true then the switch will be ON
for all the code I share the link of expo for live editing
Expo Link for Editing
You need to create a component that receives the item information, and inside the component update the state individually for each switch, otherwise the state is shared among the number of items you have.
The link for Expo is here
If you turn your results into a state you can do it link:
import React, { useEffect, useState } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Image,
ScrollView,
FlatList,
SafeAreaView,
Switch,
RefreshControl,
Vibration,
ActivityIndicator,
} from 'react-native';
import { Card, TextInput, RadioButton } from 'react-native-paper';
const results = [
{
Id: 'IySO9wUrt8',
Name: 'Los Stand',
Category: 'Mexican',
Status: true,
},
{
Id: 'IySO9wUrt8',
Name: 'Los Stand 2',
Category: 'Burger',
Status: true,
},
{
Id: 'IySO9wUrt8',
Name: 'Los Stand 3',
Category: 'BBq',
Status: true,
},
];
export default function App() {
const [data, setData] = useState(results);
const updateItem = (newItem, index) => {
// when an array is used with useState it should be treated immutable
// if the array have nested objects/arrays then you will need
// a different cloning technique
const dataClone = [...data];
const currentItem = dataClone[index];
dataClone[index] = { ...currentItem, ...newItem };
setData(dataClone);
};
const renderItem = ({ item, index }) => {
let items = [];
return (
<>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
width: 280,
}}>
<Text>{item.Name}</Text>
<Switch
key={item.Id}
style={{ alignSelf: 'center' }}
trackColor={{ false: '#767577', true: '#81b0ff' }}
thumbColor={item.Status ? '#f5dd4b' : '#f4f3f4'}
ios_backgroundColor="#3e3e3e"
onValueChange={(val) => updateItem({Status: val }, index)}
value={item.Status}
/>
</View>
</>
);
};
return (
<SafeAreaView style={styles.container}>
<FlatList
style={styles.container}
data={data}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 2,
backgroundColor: 'white',
},
textStyle: {
marginHorizontal: 20,
marginTop: 10,
color: 'black',
fontWeight: '600',
},
singleRadioButtonContainer: {
flexDirection: 'row',
alignItems: 'center',
marginRight: 10,
},
});
If converting result into state is not desireable then you can move renderItem into its own file so that it can have state of its own link:
import React, { useState } from 'react';
import { View, Switch, Text } from 'react-native';
export default function Item({ item, index }) {
const [enabled, setEnabled] = useState(item.Status)
return (
<>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
width: 280,
}}>
<Text>{item.Name}</Text>
<Switch
key={item.Id}
style={{ alignSelf: 'center' }}
trackColor={{ false: '#767577', true: '#81b0ff' }}
thumbColor={enabled ? '#f5dd4b' : '#f4f3f4'}
ios_backgroundColor="#3e3e3e"
onValueChange={setEnabled}
value={enabled}
/>
</View>
</>
);
}

Sort array by value and alphabet React Native

I get an array from firebase, it is now sorted alphabetically. If an object contains 'routes' then it will get the text 'Bekijk' button otherwise the text 'coming soon' button, what I would like is that the objects with the name 'Bekijk' are displayed first and then the other objects alphabetically order, does anyone know if that is possible?
This is my code:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, Image, ImageBackground, StatusBar, ScrollView, Dimensions, TouchableOpacity} from 'react-native';
import { Header, Icon,Button,Rating, AirbnbRating } from 'react-native-elements';
import firebase from 'react-native-firebase';
class routeScreen extends Component {
constructor(props){
super(props);
this.state = {
goverments: [],
}
}
getGovermentData = () => {
let ref = firebase.database().ref('Goverments');
ref.on('value' , snapshot =>{
var state = snapshot.val();
this.setState({
goverments: state,
})
console.log(state);
})
}
componentWillMount(){
this.getGovermentData();
}
render() {
const width = {
width: (Dimensions.get('window').width / 2),
};
return (
<ScrollView>
{
this.state.goverments.sort(function(a, b) {
if(a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if(a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
}).map((item, i) => (
<View style={[styles.cards, { backgroundColor: (i % 2 == 0) ? '#D1A96E' : '#A58657' }]}>
<View style={styles.leftcolum}>
<Text style={styles.title}>{item.name}</Text>
<Text style={styles.undertitle}>4km - 5km - 7km</Text>
<Image source={require('./assets/images/stars.png')} style={styles.stars}/>
<Button buttonStyle={{
backgroundColor: item.routes ? "#3F494B" : "#018786",
marginTop: 40,
borderRadius: 50,
}} title={item.routes ? "Bekijk" : "Coming soon"}
onPress={() => item.routes ? this.props.navigation.navigate('Location', {govermentData: item}) : '#'}
/>
</View>
<View style={styles.rightcolum}>
<Image source={{uri: item.logoUrl}} style={{width: 150, height: 68}}/>
</View>
</View>
))
}
</ScrollView>
);
}
}
const styles = StyleSheet.create({
cards:{
backgroundColor: '#D1A96E',
borderRadius: 10,
marginTop: 20,
marginRight: 10,
marginLeft: 10,
paddingLeft: 20,
paddingRight: 20,
paddingTop: 20,
paddingBottom: 20,
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start'
},
stars:{
marginTop: 10,
},
leftcolum:{
width: '50%',
},
rightcolum:{
width: '50%',
paddingTop:30,
paddingLeft:10,
},
title:{
fontSize: 17,
color: '#fff',
marginTop: 5,
fontWeight: '800',
},
undertitle:{
fontSize: 12,
color: '#fff',
fontWeight: '200',
},
button:{
backgroundColor: '#3F494B',
borderRadius: 22,
marginTop: 20,
},
valkenburg:{
backgroundColor: '#A58657',
},
gulpen:{
backgroundColor: '#EBC285',
},
logoValkenburg:{
width: '50%',
paddingTop:10,
paddingLeft:10,
},
logoGulpen:{
width: '50%',
paddingTop:30,
paddingLeft:10,
}
});
export default routeScreen;
Structure of array:
what I would like:
now the array is shown in alphabetical order, that is good, I would only like to show object 1 of Goverments at the top because it contains the value routes, with the others the value routes being empty. so if it is filled, it must show it at the top
const Goverments = [
{
name: 'Valkenburg',
},
{
name: 'Eijsden-Margeaten',
},
{
name: 'Gulpen',
routes: [],
},
];
const SortedGoverments = Goverments.sort(function(a, b) {
if(a.routes) return -1; // new check
if(b.routes) return 1; // new check
if(a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if(a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
});
console.log("Goverments : ", Goverments);
console.log("SortedGoverments : ", SortedGoverments);

Declaring array for use in React Native AutoComplete search engine

Not sure where I go about declaring the array with which I want to search from, any assistance would be appreciated. I believe my issue is that I am declaring the "services' array in the incorrect area but I am not sure where else to put it! Or if the commas are the right character to be using in between strings/services
import React, { useState, Component } from 'react';
import { StyleSheet, StatusBar, View, Text, Button, TouchableOpacity } from 'react-native';
import AutoComplete from 'react-native-autocomplete-input';
class CareProviderSequenceScreen extends Component {
constructor (props) {
super (props);
this.state = {
services: [],
query: '',
}
}
render() {
const query = this.state;
const services = {
"Pick up my Prescription",
'Pick up groceries',
'Pick up dry cleaning',
'Pick up my pet',
}
return (
<View style={styles.container}>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
//data to show in suggestion
data={services.length === 1 && comp(query, services[0].title) ? [] : services}
//default value if you want to set something in input
defaultValue={query}
/*onchange of the text changing the state of the query which will trigger
the findFilm method to show the suggestions*/
onChangeText={text => this.setState({ query: text })}
placeholder="Enter your need"
renderItem={({ item }) => (
//you can change the view you want to show in suggestion from here
<TouchableOpacity onPress={() => this.setState({ query: item.title })}>
<Text style={styles.itemText}>
{item.title} ({item.release_date})
</Text>
</TouchableOpacity>
)}
/>
<View style={styles.descriptionContainer}>
{services.length > 0 ? (
<Text style={styles.infoText}>{this.state.query}</Text>
) : (
<Text style={styles.infoText}>Enter The Film Title</Text>
)}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
flex: 1,
padding: 16,
marginTop: 40,
},
autocompleteContainer: {
backgroundColor: '#ffffff',
borderWidth: 0,
},
descriptionContainer: {
flex: 1,
justifyContent: 'center',
},
itemText: {
fontSize: 15,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
},
infoText: {
textAlign: 'center',
fontSize: 16,
},
});
export default CareProviderSequenceScreen ;
CareProviderSequenceScreen .navigationOptions = () => ({
title: "Home & Personal Care",
headerTintColor: '#9EBBD7',
headerStyle: {
height: 65,
backgroundColor: '#1E5797',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.20,
shadowRadius: 1.41,
elevation: 2,}
});
First, you are assigning an object to services array.
Second, you are not accessing the query state properly. It should be
const { query } = this.state

Realm React Native get crash

I am using Realm for the first time, I have written the simple code in app.js
import React, { Component } from 'react';
import { StyleSheet, Platform, View, Image, Text, TextInput, TouchableOpacity, Alert } from 'react-native';
var Realm = require('realm');
let realm ;
export default class App extends Component{
constructor(){
super();
this.state = {
Student_Name : '',
Student_Class : '',
Student_Subject : ''
}
realm = new Realm({
schema: [{name: 'Student_Info',
properties:
{
student_id: {type: 'int', default: 0},
student_name: 'string',
student_class: 'string',
student_subject: 'string'
}}]
});
}
add_Student=()=>{
realm.write(() => {
var ID = realm.objects('Student_Info').length + 1;
realm.create('Student_Info', {
student_id: ID,
student_name: this.state.Student_Name,
student_class: this.state.Student_Class,
student_subject : this.state.Student_Subject
});
});
Alert.alert("Student Details Added Successfully.")
}
render() {
var A = realm.objects('Student_Info');
var myJSON = JSON.stringify(A);
return (
<View style={styles.MainContainer}>
<TextInput
placeholder="Enter Student Name"
style = { styles.TextInputStyle }
underlineColorAndroid = "transparent"
onChangeText = { ( text ) => { this.setState({ Student_Name: text })} }
/>
<TextInput
placeholder="Enter Student Class"
style = { styles.TextInputStyle }
underlineColorAndroid = "transparent"
onChangeText = { ( text ) => { this.setState({ Student_Class: text })} }
/>
<TextInput
placeholder="Enter Student Subject"
style = { styles.TextInputStyle }
underlineColorAndroid = "transparent"
onChangeText = { ( text ) => { this.setState({ Student_Subject: text })} }
/>
<TouchableOpacity onPress={this.add_Student} activeOpacity={0.7} style={styles.button} >
<Text style={styles.TextStyle}> CLICK HERE TO ADD STUDENT DETAILS </Text>
</TouchableOpacity>
<Text style={{marginTop: 10}}>{myJSON}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
MainContainer :{
flex:1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: (Platform.OS) === 'ios' ? 20 : 0,
margin: 10
},
TextInputStyle:
{
borderWidth: 1,
borderColor: '#009688',
width: '100%',
height: 40,
borderRadius: 10,
marginBottom: 10,
textAlign: 'center',
},
button: {
width: '100%',
height: 40,
padding: 10,
backgroundColor: '#4CAF50',
borderRadius:7,
marginTop: 12
},
TextStyle:{
color:'#fff',
textAlign:'center',
}
});
Now I am getting the error like this in picture http://prntscr.com/mym0zo, as I have already said, I am using the realm for the very first time, so can't understand the problem.
Please help me get this resolved.
My dependancies are
"dependencies": {
"react": "16.8.3",
"react-native": "0.59.1",
"realm": "^2.25.0"
},

Categories

Resources