delete list element using filter method - javascript

I am working on todo list in native , i have a function called onDelete but when i click on it , it delete all element in list and after then program crashed.
this is my main file where i have stored value as key , value pair
export default function App() {
const [courseGoal, setCourseGoal] = useState([]);
const [count, setCount] = useState('');
const submitHandler = () => {
setCourseGoal((currGoal) => [
...currGoal,
{ key: Math.random().toString(), value: count },
]);
};
console.log('App', courseGoal)
return (
<View style={styles.container}>
<SearchBar
setCourseGoal={setCourseGoal}
count={count}
setCount={setCount}
submitHandler={submitHandler}
/>
<ListItem courseGoal={courseGoal} setCourseGoal={setCourseGoal} courseGoal={courseGoal}/>
</View>
);
}
this is my list component where i am facing issue, you can see ondelete here.
import React from "react";
import { StyleSheet, Text, TouchableOpacity } from "react-native";
import { FlatList } from "react-native-web";
export default function ListItem(props) {
const onDelete = (goalId) => {
props.setCourseGoal((currGoal) => {
currGoal.filter((goal) => goal.key !== goalId);
console.log("clicked", props.courseGoal[0].key);
});
};
return (
<FlatList
data={props.courseGoal}
keyExtractor={(item, index) => item.key}
renderItem={(itemData) => (
<TouchableOpacity
onPress={onDelete.bind(itemData.item.key)}
activeOpacity={0.2}
>
<Text style={styles.listData}>{itemData.item.value}</Text>
{console.log(itemData.item.key)}
</TouchableOpacity>
)}
/>
);
}
this is my main component where i have my search input
import React from "react";
import { View, Text, StyleSheet, Pressable, TextInput } from "react-native";
export default function SearchBar(props) {
const onInputHandler = (value) => {
props.setCount(value);
};
return (
<View style={styles.searchBox}>
<Pressable style={styles.submitBtn} title="Click Me !">
<Text>☀️</Text>
</Pressable>
<TextInput
style={styles.searchInput}
placeholder="Enter Goal"
onChangeText={onInputHandler}
/>
<Pressable
style={styles.submitBtn}
title="Click Me !"
onPress={props.submitHandler}
>
<Text>🔥🔥</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
searchBox: {
flexDirection: "row",
justifyContent: "space-around",
},
searchInput: {
width: "90%",
textAlign: "center",
padding: 10,
// color: 'white',
borderRadius: 10,
borderWidth: 1,
marginHorizontal: 5,
},
submitBtn: {
color: "black",
justifyContent: "space-around",
padding: 10,
borderRadius: 10,
borderWidth: 1,
},
});

You have to return the filtered array from your onDelete function
const onDelete = (goalId) => {
props.setCourseGoal((currGoal) => {
return currGoal.filter((goal) => goal.key !== goalId);
});
};

Related

React Context is not updating Data

I have created a React Context API, I have stored information such as first_name, hobbies, DOB etc in it. I have crated a state in the context file and a function that changes the state when called. I am using the context in SignUpForm1.js and SignUpForm2.js, I am trying to update the state of context variables when ever there is a change in the text field, but the data in the context is not updating.
UserData.js (Context)
import React from "react";
import { useState } from "react";
import {Text} from 'react-native';
import { createContext } from "react";
const SignUpContext = React.createContext({});
const UserData = (props)=>{
var state = {
pref_pronoun: "",
DOB: "",
course: "",
first_name: "",
hobby_1: "",
hobby_2: "",
hobby_3: "",
hobby_4: "",
hobby_5: "",
home_city: "",
last_name: "",
nationality: "",
student_email: "",
university: "",
}
const [userDetails , setDetails] = useState(state);
const updateFormData = (field, value) => {
setDetails({ [field]: value });
console.log(state);
};
return (
<SignUpContext.Provider value = {{state, updateFormData}}>
{props.children}
</SignUpContext.Provider>
)
}
export {SignUpContext, UserData} ;
SignUpForm1.js
import {
Image,
Text,
StyleSheet,
View,
StatusBar,
ScrollView,
RefreshControl,
} from "react-native";
import DropDown from "./DropDown";
import Input from "./Input";
import {
KeyboardAvoidingView,
TouchableWithoutFeedback,
Keyboard,
} from "react-native";
import { useCallback, useContext, useState } from "react";
import CustomButton from "./CustomButton";
import { useNavigation } from "#react-navigation/native";
import DateTimePickerModal from "react-native-modal-datetime-picker";
import { Button } from "react-native";
import { SignUpContext, UserData } from "./GlobalUtil/UserData";
const HideKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
function SignUpForm1() {
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
const s_context = useContext(SignUpContext);
const showDatePicker = () => {
setDatePickerVisibility(true);
};
const hideDatePicker = () => {
setDatePickerVisibility(false);
};
const navigation = useNavigation();
const NationalityData = ["Football", "Cricket", "Programmming", "Coding"];
const [refreshing, setRefreshing] = useState(false);
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
setRefreshing(false);
}, 2000);
}, []);
const statusBarHeight = Platform.OS === "ios" ? 50 : StatusBar.currentHeight;
return (
<KeyboardAvoidingView behavior="padding">
<HideKeyboard>
<View
style={{
height: "100%",
width: "100%",
backgroundColor: "#f1be63",
}}
>
<View
style={{ backgroundColor: "#f1be63", height: statusBarHeight }}
>
<StatusBar barStyle="dark-content" />
</View>
<ScrollView
contentContainerStyle={styles.rootContainer}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
/>
}
>
<Image
source={require("../assets/aeroplane.png")}
style={styles.image}
resizeMode="contain"
/>
<Text style={styles.header}>Let's get you set up</Text>
<Text style={styles.lowerHeader}>
(we promise that it won't take long)
</Text>
<View style={[styles.textFieldsContainer]}>
<View style={{ alignItems: "center" }}>
<Input
isLabel={true}
label="Preferred Pronoun"
placeholder="He/Him"
onChangeText={(text) => {
s_context.updateFormData("pref_pronoun", text);
}}
/>
<Input
isLabel={true}
label="First Name"
placeholder="Cameron"
onChangeText={(text) => {
s_context.updateFormData("first_name", text);
}}
/>
<Input
isLabel={true}
label="Last Name"
placeholder="Cox"
onChangeText={(text) => {
s_context.updateFormData("last_name", text);
}}
/>
<View
style={{
backgroundColor: "white",
width: "80%",
borderRadius: 5,
marginTop: 10,
}}
>
<Button
title="Date of Birth"
onPress={showDatePicker}
color="gray"
/>
</View>
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
onConfirm={(date) => {
s_context.updateFormData('dob', date);
hideDatePicker();
}}
onCancel={hideDatePicker}
buttonTextColorIOS="white"
pickerContainerStyleIOS={{ backgroundColor: "#D89D35" }}
isDarkModeEnabled
/>
</View>
<View style={{ alignItems: "center" }}>
<DropDown
data={NationalityData}
placeholder="Nationality"
onSelect={(selectedItem, index) => {
s_context.updateFormData("nationality", selectedItem);
}}
/>
<DropDown
data={NationalityData}
placeholder="University"
onSelect={(selectedItem, index) => {
s_context.updateFormData("university", selectedItem);
}}
/>
<DropDown
data={NationalityData}
placeholder="Course"
onSelect={(selectedItem, index) => {
s_context.updateFormData("course", selectedItem);
}}
/>
<DropDown
data={NationalityData}
placeholder="HomeTown City"
onSelect={(selectedItem, index) => {
s_context.updateFormData("homeCity", selectedItem);
}}
/>
<CustomButton
isBorder={true}
title="Next"
onPress={() => {
navigation.navigate("SignUp2");
}}
/>
</View>
</View>
</ScrollView>
</View>
</HideKeyboard>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
rootContainer: {
height: "125%",
justifyContent: "flex-start",
alignItems: "center",
marginTop: 24,
},
textFieldsContainer: {
width: "100%",
flex: 1,
},
image: {
width: "25%",
height: "10%",
marginTop: 24,
},
header: {
color: "white",
fontSize: 26,
fontWeight: "bold",
marginVertical: 6,
},
lowerHeader: {
color: "white",
fontSize: 12,
marginBottom: 24,
},
});
export default SignUpForm1;
SignUpForm2.js
import {
View,
Text,
TouchableWithoutFeedback,
StyleSheet,
StatusBar,
ScrollView,
} from "react-native";
import { KeyboardAvoidingView } from "react-native";
import { Avatar } from "react-native-elements";
import Input from "./Input";
import DropDown from "./DropDown";
import { Keyboard } from "react-native";
import { Platform } from "react-native";
import { useNavigation } from "#react-navigation/native";
import CustomButton from "./CustomButton";
import { useState, useContext } from "react";
import { createNewUser } from "./util/auth";
import { SignUpContext, UserData } from "./GlobalUtil/UserData";
const HideKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
function SignUpForm2() {
const s_context = useContext(SignUpContext);
async function FinishBtnHandler()
{
console.log("Creating New User");
console.log("Email: " + emailText.trim());
console.log("Password: " + passwordText.trim());
await createNewUser(emailText.trim(), passwordText.trim());
}
const navigation = useNavigation();
const hobbiesData = ["Football", "Cricket", "Programmming", "Coding"];
const [emailText, setEmailText] = useState("");
function handleEmailText(newText) {
console.log("Email: " + newText);
setEmailText(newText);
}
const [passwordText, setPasswordText] = useState("");
function handlePasswordText(newText) {
console.log("Password: " + newText);
setPasswordText(newText);
}
function avatarPressHandler() {
console.log("Pressed!");
}
const statusBarHeight = Platform.OS === "ios" ? 50 : StatusBar.currentHeight;
return (
<KeyboardAvoidingView behavior="padding" style={{ flex: 1 }}>
<HideKeyboard>
<ScrollView>
<View
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
zIndex: 999,
}}
>
<View
style={{
backgroundColor: "#f1be63",
height: statusBarHeight,
}}
>
<StatusBar barStyle="dark-content" />
</View>
</View>
<View style={[styles.rootContainer, { paddingBottom: 48 }]}>
<View style={styles.lowerContainer}>
<Text style={styles.primaryText}>You're almost there!</Text>
<Avatar
rounded
size={170}
containerStyle={{ alignSelf: "center", marginTop: 24 }}
//icon={{ name: "user", type: "font-awesome" }}
overlayContainerStyle={{ backgroundColor: "#f1be63" }}
source={{
uri: "https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg",
}}
>
<Avatar.Accessory size={20} onPress={avatarPressHandler} />
</Avatar>
<Text
style={[
styles.secondaryText,
{ marginBottom: 8, marginTop: 16 },
]}
>
Express yourself & customize your avatar
</Text>
<Input
isLabel={true}
label="Student Email"
placeholder="cce22rnu#uea.ac.uk"
onChangeText={handleEmailText}
defaultValue={emailText}
/>
<Input
isLabel={true}
label="Create Password"
placeholder="iLoveyoushakila123"
onChangeText={handlePasswordText}
defaultValue={passwordText}
/>
<Input
isLabel={true}
label="Confirm Password"
placeholder="iLoveyoushakila123"
/>
<Text style={styles.secondaryText}>
Now the exciting part - select your top 5 hobbies
</Text>
<View style={{ alignItems: "center", marginTop: 16 }}>
<DropDown
data={hobbiesData}
onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_1", selectedItem);
}}
/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_2", selectedItem);
}}/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_3", selectedItem);
}}/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_4", selectedItem);
}}/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_5", selectedItem);
}}/>
<CustomButton
isBorder={true}
title="Finish"
/*onPress={()=>{navigation.navigate("ConfirmId")}}*/ onPress={
FinishBtnHandler
}
/>
</View>
</View>
</View>
</ScrollView>
</HideKeyboard>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
rootContainer: {
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
backgroundColor: "#f1be63",
marginTop: 48,
backgroundColor: "#f1be63",
},
lowerContainer: {
flex: 1,
width: "100%",
alignItems: "center",
},
primaryText: {
color: "white",
fontSize: 24,
fontWeight: "bold",
},
secondaryText: {
marginTop: 8,
color: "white",
fontSize: 12,
fontWeight: "bold",
},
});
export default SignUpForm2;
You need to pass your userDetails state variable to the context, not the initial state value
<SignUpContext.Provider value={{ state: userDetails, updateFormData }}>
{props.children}
</SignUpContext.Provider>
Passing the initial state object will not see any updates you make.
Also, you should use the functional updates format to dynamically set properties in your state
setDetails((prev) => ({ ...prev, [field]: value }));
Finally, console logging state is a pointless exercise that often gives unexpected results. Just don't do it
The issue is that you are using state instead of userDetails in the updateFormData function. The state variable is never updated and remains the same initial value. To fix this, you should use setDetails instead of setState in the updateFormData function.
const updateFormData = (field, value) => {
setDetails({ ...userDetails, [field]: value });
console.log(userDetails);
};
Also, you are passing state in the SignUpContext.Provider value. You should pass userDetails instead of state.
return (
<SignUpContext.Provider value={{ userDetails, updateFormData }}>
{props.children}
</SignUpContext.Provider>
);

React Navigation and React Context

In our App we use a tab navigation and a stack navigation for each tab. We want an array of devices where we could add and delete devices. The array should be available on every tab.
This is our provider
import React from 'react'
const DevicesContext = React.createContext('')
export default DevicesContext
This is our app.js
import React, {useState} from 'react';
import uuid from 'react-native-uuid';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { Feather } from '#expo/vector-icons';
import { MaterialIcons } from '#expo/vector-icons';
import HomeStackScreen from "./components/home/HomeStackScreen";
import ConnectStackScreen from "./components/connect/ConnectStackScreen";
import SettingsStackScreen from "./components/settings/SettingsStackScreen";
import DevicesContext from "./components/context/DevicesContext";
const Tab = createMaterialBottomTabNavigator();
const deleteItem = (id) => {
setDevices(prevDevice => {
return prevDevice.filter(device => device.id != id)
})
console.log(devices)
}
const addItem = (device) => {
setDevices(prevDevices => {
return [{id: uuid.v4(), name:device}, ...prevDevices];
})
}
function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Home"
activeColor="#E4E4E4"
inactiveColor="#000000"
shifting={true}
labelStyle={{ fontSize: 12 }}
barStyle={{ backgroundColor: '#8DFFBB' }}
>
<Tab.Screen
name="Devices"
component={ConnectStackScreen}
options={{
tabBarLabel: 'Geräte',
tabBarIcon: ({ color }) => (
<MaterialIcons name="devices" size={24} color={color} />
),
}}
/>
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="home" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Settings"
component={SettingsStackScreen}
options={{
tabBarLabel: 'Einstellungen',
tabBarIcon: ({ color }) => (
<Feather name="settings" size={24} color={color} />
),
}}
/>
</Tab.Navigator>
);
}
export default function App() {
const [devices, setDevices] = useState([
{id: uuid.v4(), name: 'thing 1', ip: 5},
{id: uuid.v4(), name: 'thing 2', ip: 2},
{id: uuid.v4(), name: 'thing 3', ip: 6},
{id: uuid.v4(), name: 'thing 4', ip: 10},
])
return (
<DevicesContext.Provider value={devices}>
<NavigationContainer>
<MyTabs />
</NavigationContainer>
</DevicesContext.Provider>
);
}
this is our connect screen where we can add devices
import React, {useContext, useState} from 'react';
import {Text, View, Button, FlatList, StyleSheet, TouchableOpacity, Image} from 'react-native';
import uuid from 'react-native-uuid';
import ListItem from "../shared/ListItem";
import AddItem from "../shared/AddItem";
import DevicesContext from "../context/DevicesContext";
function ConnectScreen( {navigation}) {
const [devices, setDevices] = useState(useContext(DevicesContext));
const deleteItem = (id) => {
setDevices(prevDevice => {
return prevDevice.filter(device => device.id != id)
})
console.log(devices)
}
const addItem = (device) => {
setDevices(prevDevices => {
return [{id: uuid.v4(), name:device}, ...prevDevices];
})
}
return (
<View style={{padding: 10, flex: 1, justifyContent: 'center'}}>
<View style={styles.AddNormal}>
<AddItem addItem={addItem}></AddItem>
<FlatList style={styles.List} data={devices} renderItem={({item}) => (
<ListItem item={item} deleteItem={deleteItem}></ListItem>
)}/>
</View>
<View style={styles.AddQr}>
<Image source={require('../../img/qr-code-url.png')} style={{ width: 150, height: 150, marginBottom: 10 }} />
<Text style={{ textAlign: 'center', marginBottom: 10 }}>Du kannst außerdem ein Gerät durch das scannen eines Qr-Code hinzufügen</Text>
<TouchableOpacity onPress={() => navigation.navigate('QrCode')}style={styles.btn}>
<Text style={styles.btnText}>Qr-Code scannen</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
List: {
backgroundColor: '#E4E4E4',
},
AddNormal: {
padding: 10, flex: 1,
},
AddQr: {
backgroundColor: '#E4E4E4',
padding: 30,
flex: 1,
marginTop: 20,
marginBottom: 20,
alignItems: 'center'
},
btn: {
backgroundColor: '#8DFFBB',
padding: 9,
margin: 10,
},
btnText: {
color: '#000',
fontSize: 20,
textAlign: 'center',
}
});
export default ConnectScreen;
and this is our main screen
import React, {useState, useContext, useEffect} from 'react';
import {Button, FlatList, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View} from "react-native";
import {ServerOnOffSwitch, SendMessage} from "./network";
import DevicesContext from "../context/DevicesContext";
const Item = ({ item, onPress, backgroundColor, textColor }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, backgroundColor]}>
<Text style={[styles.title, textColor]}>{item.name}</Text>
</TouchableOpacity>
);
function HomeScreen (){
const [devices, setDevices] = useState(useContext(DevicesContext));
const deleteItem = (id) => {
setDevices(prevDevice => {
return prevDevice.filter(device => device.id != id)
})
}
const [selectedId, setSelectedId] = useState(null);
const renderItem = ({ item }) => {
const backgroundColor = item.id === selectedId ? "#b5b5b5" : "#ededed";
const color = item.id === selectedId ? 'white' : 'black';
return (
<Item
item={item}
onPress={() => setSelectedId(item.id)}
backgroundColor={{ backgroundColor }}
textColor={{ color }}
/>
);
};
return (
<View style={{padding: 10, flex: 1, justifyContent: 'center'}}>
<View style={{padding: 10, flex: 1}}>
<Text style={styles.DeviceHeader}>Gerät auswählen</Text>
<FlatList
data={devices}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
/>
</View>
<View style={{padding: 10, flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<SendMessage item={selectedId}></SendMessage>
<ServerOnOffSwitch></ServerOnOffSwitch>
</View>
</View>
);
}
const styles = StyleSheet.create({
DeviceHeader: {
fontSize: 22,
paddingBottom: 10,
},
item: {
padding: 10,
backgroundColor: '#f8f8f8',
borderBottomWidth: 1,
borderColor: '#eee',
},
title: {
fontSize: 18,
},
});
export default HomeScreen;
If we add devices in our Connect screen they are getting updated there but not on the homescreen.
Thanks for your help:)
to update context from nested component you must pass the methode setDevices tha will update it.
to pass it do the following steps :
your context shoud be
import React from 'react'
const DevicesContext = React.createContext({
devices: [],
setDevices: () => {}, //methode will update context value
})
export default DevicesContext
App.js should be
//define state
const [devices, setDevices] = React.useState([])
//define constexValue
//we will pass `devices` and also `setDevices` that will update it.
const DevicesContextValue = React.useMemo(() => ({ devices, setDevices}), [devices]);
return (
<DevicesContext.Provider value={DevicesContextValue}>
...
</DevicesContext.Provider>
);
ConnectScreen.js should be
function ConnectScreen(){
const {devices, setDevices} = useContext(DevicesContext);
//call setDevices will update context
....
}
HomeScreen.js should be
function HomeScreen (){
const {devices, setDevices} = useContext(DevicesContext);
//use devices from context in your flatlist and when the context update the result will show in flatlist
....
}

How can i get back my data list after searching by words?

i use Flatlist and search by words on renderHeader() function. I can filter but when i delete letters, i couldn't get main list again. I think there is a logic problem but i couln't find after trying something...
i've got a new one when i fixed problem. I tried to fix but i couldn't do that, i should put the problem in front of experts :)
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
const Flatlistexample = () => {
//main list state
let [list, setList] = useState(data);
//search state
const [search, setSearch] = useState('');
//search filter
searchFilter = text => {
// onChangeText
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}
//search function
renderHeader = () =>{
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
//setStates
searchFilter(text)
setSearch(text)
}}></TextInput>
<Text
style={{
alignItems: 'flex-start',
color: 'black',
fontSize: 22,
}}>
{search}
</Text>
</View>
)
}
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
data={list}
renderItem={({item, index}) => {
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb'},
]}>
<Image style={styles.profile} source={{uri: item.picture}} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
//called search function
ListHeaderComponent={renderHeader()}
/>
</SafeAreaView>
)
}
export default Flatlistexample
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: 'gray',
},
profile: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: 10,
},
rightside: {
marginLeft: 20,
justifyContent: 'space-between',
marginVertical: 5,
},
name: {
fontSize: 22,
marginBottom: 10,
},
searchContainer: {
padding: 10,
borderWidth: 2,
borderColor: 'gray',
},
textInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
},
})
Thanks for your help
Filter Data
onSearchText = (value) => {
this.setState({searchText: value})
if(value.trim() == "" || value == null){
this.setState({list: this.state.list}
} else {
let filter = this.state.list.fillter(data => {
// data fillter logic //
return data;
})
this.setState({filterData: filter})
}
Render FlatList
<FlatList
extradata={this.state}
data={searchText ? filterData : list}
/>
I fixed...
How?
My main data state is constant, i'm filtering on data list with filter state. So my data list doesn't change anytime.
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
const Flatlistexample = () => {
//main list state
let [list, setList] = useState(data)
//search state
const [search, setSearch] = useState('')
//filter state
const [updated, setUpdated] = useState(data)
//search filter
searchFilter = text => {
// onChangeText
if (text) {
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1
})
setUpdated(newData)
}
//search function
renderHeader = () => {
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
searchFilter(text)
setSearch(text)
}}></TextInput>
<Text
style={{
alignItems: 'flex-start',
color: 'black',
fontSize: 22,
}}>
{search}
</Text>
</View>
)
}
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
//i'm showing filter state
data={updated}
renderItem={({item, index}) => {
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb'},
]}>
<Image style={styles.profile} source={{uri: item.picture}} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
//called search function
ListHeaderComponent={renderHeader()}
/>
</SafeAreaView>
)
}
export default Flatlistexample
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: 'gray',
},
profile: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: 10,
},
rightside: {
marginLeft: 20,
justifyContent: 'space-between',
marginVertical: 5,
},
name: {
fontSize: 22,
marginBottom: 10,
},
searchContainer: {
padding: 10,
borderWidth: 2,
borderColor: 'gray',
},
textInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
},
})
/*
else if(text.length > uzunluk){
setList(data)
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}else if(text.length<uzunluk){
setList(data)
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}
*/

render data in FlatList React Native (expo cli) from firebase realtime database?

I'm working on a ToDo app that is connected to the Firebase real-time database. Everything works fine. I can also store data in the Firebase database, but the problem is that I cannot get any data from the database. I want to render data in ScrollView so that the data can be displayed in ScrollView when I open my app.
I'm getting error: ReferenceError: noteArray is not defined <FlatList data={noteArray}
I have uploaded my whole code [codesandbox.io/s/stupefied-snowflake-1lddp?file=/src/App.js][1]
Main.js
import React, { Component } from "react";
import {
StyleSheet,
Text,
View,
TextInput,
TouchableOpacity,
FlatList
} from "react-native";
import Note from "./note";
import firebase from "./firebase";
export default class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
noteArray: [],
noteText: ""
};
}
componentDidMount() {
this.listenForNotes();
}
listenForNotes() {
firebase
.database()
.ref(`todos`)
.on("value", function (snapshot) {
const notes = [];
snapshot.forEach((child) => {
notes.push({
note: child.val().name,
date: child.val().date,
key: child.key
});
});
this.setState({
noteArray: notes
});
});
}
adTask() {
if (this.state.noteText) {
var date = new Date();
var database = firebase.database().ref("todos");
var key = database.push().key;
var todo = {
date:
date.getDay() +
"/" +
(date.getMonth() + 1) +
"/" +
date.getFullYear(),
note: this.state.noteText,
key: key
};
database.child(key).set(todo);
this.setState({ noteText: "" });
}
}
deleteNote(key) {
// your delete note function
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Todo</Text>
</View>
<FlatList
data={this.state.noteArray}
renderItem={({ item, index }) => {
return (
<Note
key={item.key}
note={item.note}
date={item.date}
deleteMethod={() => this.deleteNote(item.key)}
/>
);
}}
key={(item) => `${item.key}`}
/>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
onChangeText={(noteText) => this.setState({ noteText })}
value={this.state.noteText}
placeholder="Enter Task"
placeholderTextColor="white"
underlineColorAndroid="transparent"
></TextInput>
</View>
<TouchableOpacity
onPress={this.adTask.bind(this)}
style={styles.addButton}
>
<Text style={styles.addButtonText}>Add</Text>
</TouchableOpacity>
</View>
);
}
}
note.js
import React from "react";
import { StyleSheet, Text, View, TouchableOpacity } from "react-native";
export default class Note extends React.Component {
constructor(props) {
super(props);
}
render() {
const { note, date, key, deleteMethod } = this.props;
return (
<View key={key} style={styles.note}>
<Text style={styles.noteText}>{note}</Text>
<Text style={styles.noteDate}>{date}</Text>
<TouchableOpacity onPress={deleteMethod} style={styles.noteDelete}>
<Text style={styles.noteDeleteText}>
<AntDesign name="delete" size={24} color="black" />
</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
note: {
position: "relative",
padding: 20,
paddingRight: 100,
borderBottomWidth: 2,
borderBottomColor: "#ededed"
},
noteText: {
fontWeight: "bold",
fontSize: 18,
paddingLeft: 20,
borderLeftWidth: 10,
borderLeftColor: "#e91e63"
},
noteDate: {
paddingLeft: 20,
borderLeftWidth: 10,
borderLeftColor: "#e91e63"
},
noteDelete: {
position: "absolute",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#2980b9",
padding: 10,
top: 10,
bottom: 10,
right: 10
},
noteDeleteText: {
color: "white"
}
});
[1]: http://codesandbox.io/s/stupefied-snowflake-1lddp?file=/src/App.js
it should be this.state.noteArray since noteArray is a state variable.
there are couple of errors in the code sandbox
<FlatList
data={noteArray}
renderItem={({ item, index }) => {
should be
<FlatList
data={this.state.noteArray}
renderItem={({ item, index }) => {
and key, should be item.key:
deleteMethod={() => this.deleteNote(key)}
should be
deleteMethod={() => this.deleteNote(item.key)}
this.setState doesn't exist is because you have a function instead of an array function. change it to the following should work:
.on("value", snapshot => {
const notes = [];
snapshot.forEach((child) => {
notes.push({
note: child.val().name,
date: child.val().date,
key: child.key
});
});
this.setState({noteArray: notes});
});

route.params not passing properly in my React.js App

I'm trying to figure out why my app isn't working properly. The basic premise is that that the user can choose the various types of cards they want to review. These are broken down into various types and are chosen via checkboxes. This array of settings is then passed to another screen where I take my data from firebase and convert it into an array. These arrays are then compared against one another and if the correct criteria is met, they are added to a new deck. This new deck is then rendered and moved through using a previous and next button. Any help would be appreciated.
My current error is saying length is undefined because when building the deck I need to go through the initial deck of cards (the firebase array).
Current error:
×
TypeError: Cannot read property 'length' of undefined
buildDeck
C:/Users/Langley/Desktop/ArticCards/screens/CardScreen.js:39
36 | let deck = new Array();
37 |
38 | for(var i = 0; i < passDeck.length; i++){
> 39 | for(var j = 0; j < currentSettings.length; j++){
| ^ 40 | if((passDeck.cType[i] == currentSettings[j].arType) && (currentSettings[j].addCV == true)){
41 | deck.push(passDeck[i]);
42 | }
HomeScreen
import React, { useState, useEffect } from "react";
import { StyleSheet, Text, Keyboard, TouchableOpacity, View, TouchableWithoutFeedback, Image } from "react-native";
import { Button } from "react-native-elements";
import { Feather } from "#expo/vector-icons";
import { initArticDB, setupArticListener } from '../helpers/fb-settings';
const HomeScreen = ({route, navigation}) => {
const [ deck, setDeck] = useState([]);
useEffect(() => {
try {
initArticDB();
} catch (err) {
console.log(err);
}
setupArticListener((items) => {
setDeck(items);
});
}, []);
useEffect(() => {
if(route.params?.articCard){
setCard({imageUrl: state.imageUrl, word: state.word, aType: state.aType, cType: state.cType, mastery: state.mastery})
}
if(route.params?.deck){
setDeck({imageUrl: state.imageUrl, word: state.word, aType: state.aType, cType: state.cType, mastery: state.mastery})
}
if(route.params?.articType){
setArticType({arType: state.arType, addCV: state.addCV})
}
}, [route.params?.articType, route.params?.deckeck, route.params?.articCard] );
navigation.setOptions({
headerRight: () => (
<TouchableOpacity
onPress={() =>
navigation.navigate('Settings')
}
>
<Feather
style={styles.headerButton}
name="settings"
size={24}
color="#fff"
/>
</TouchableOpacity>
),
headerLeft: () => (
<TouchableOpacity
onPress={() =>
navigation.navigate('About')
}
>
<Text style={styles.headerButton}> About </Text>
</TouchableOpacity>
),
});
return(
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.container}>
<Text style={styles.textmenu}>Welcome to Artic Cards</Text>
<Text style={styles.textsubmenu}>Press Start to Begin!</Text>
<Image source={require('../assets/5-snowflake-png-image.png')}
style={{width: 300, height: 300, alignSelf: 'center'}}/>
<Button
title="Start"
style={styles.buttons}
onPress={() => navigation.navigate('Cards',
{passDeck: deck})}
/>
<Button
title="Progress"
style={styles.buttons}
onPress={() => navigation.navigate('Progress')}
/>
<Button
title="Customize"
style={styles.buttons}
onPress={() => navigation.navigate('Customize')}
/>
</View>
</TouchableWithoutFeedback>
);
};
const styles = StyleSheet.create({
container: {
padding: 10,
backgroundColor: '#E8EAF6',
flex: 1,
justifyContent: 'center'
},
textmenu: {
textAlign: 'center',
fontSize: 30
},
textsubmenu:{
textAlign: 'center',
fontSize: 15
},
headerButton: {
color: '#fff',
fontWeight: 'bold',
margin: 10,
},
buttons: {
padding: 10,
},
inputError: {
color: 'red',
},
input: {
padding: 10,
},
resultsGrid: {
borderColor: '#000',
borderWidth: 1,
},
resultsRow: {
flexDirection: 'row',
borderColor: '#000',
borderBottomWidth: 1,
},
resultsLabelContainer: {
borderRightWidth: 1,
borderRightColor: '#000',
flex: 1,
},
resultsLabelText: {
fontWeight: 'bold',
fontSize: 20,
padding: 10,
},
resultsValueText: {
fontWeight: 'bold',
fontSize: 20,
flex: 1,
padding: 10,
},
});
export default HomeScreen;
SettingScreen
import React, {useState, useEffect} from 'react';
import {StyleSheet, TouchableOpacity, View} from "react-native";
import {Text, CheckBox} from "react-native-elements";
import {FlatList } from "react-native-gesture-handler";
//this is broken some how can't figure out why.
const SettingsScreen = ({route, navigation}) =>{
//create a screen with checkbox fields. One for the consonant-vowel field and the other for the alphabet.
//Both of which will be using flatlists preferably side by side
//A card will only be counted if it meets both values being marked true (category and alpha)
const [articType, setArticType] = useState([
{arType: 'CV', addCV: true},
{arType: 'VC', addCV: true},
{arType: 'VV', addCV: true},
{arType: 'VCV', addCV: true},
{arType: 'CVCV', addCV: true},
{arType: 'C1V1C1V2', addCV: true},
{arType: 'C1V1C2V2', addCV: true},
]);
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={() => navigation.navigate('Home')}>
<Text style={styles.headerButton}> Cancel </Text>
</TouchableOpacity>
),
headerLeft: () => (
<TouchableOpacity
onPress={() => {
// navigate back with new settings.
navigation.navigate('Home', {
currentSetting: articType
});
}}
>
<Text style={styles.headerButton}> Save </Text>
</TouchableOpacity>
),
});
const renderCVType = ({index, item}) =>{
return(
<CheckBox
title={item.arType}
checked={item.addCV}
onPress={() => {
let newArr = [... articType];
newArr[index] = {...item, addCV: !item.addCV};
setArticType(newArr);
console.log(newArr);
}}
/>
)
}
return(
<View style={styles.container}>
<Text style={styles.textmenu}>Artic Type</Text>
<Text style={styles.textsubmenu}>Select what words to include based on their cononants and vowels</Text>
<FlatList
keyExtractor={(item) => item.arType}
data={articType}
renderItem={renderCVType}
/>
</View>
)
}
const styles = StyleSheet.create({
container: {
padding: 10,
backgroundColor: '#E8EAF6',
flex: 1,
},
textmenu: {
textAlign: 'center',
fontSize: 30
},
textsubmenu:{
textAlign: 'center',
fontSize: 15
},
});
export default SettingsScreen;
CardScreen
import React, { useState, useRef, useEffect } from "react";
import { StyleSheet, Text, View } from "react-native";
import { Button, Card } from "react-native-elements";
import { updateArtic } from "../helpers/fb-settings";
import { State } from "react-native-gesture-handler";
//Cannot navigate to this page, not sure why
//general formatting and importing of the deck. Probably put shuffle function here with imported array
//Next and previous buttons should bascially refresh page and give next or previous card
//mastery probably will require setupArticListener (this needs clarification though)
//Deck will be imported here and the information from SettingScreen will be imported here as well
const CardScreen = ({route, navigation}) =>{
const { currentSettings, passDeck } = route.params;
const renderCard = ({index, item}) => {
<View>
<Card
title={item.word}
image={{uri: item.imageUrl}}>
<Text> {item.cType} </Text>
</Card>
</View>
}
const renderMastery = ({index, item}) =>{
return(
<CheckBox
title={'Mastered?'}
checked={!item.mastery}
onPress={() => {
updateArtic({ ...item, mastery: !item.mastery });
}}
/>
)
}
function buildDeck(){
let deck = new Array();
for(var i = 0; i < passDeck.length; i++){
for(var j = 0; j < currentSettings.length; j++){
if((passDeck.cType[i] == currentSettings[j].arType) && (currentSettings[j].addCV == true)){
deck.push(passDeck[i]);
}
}
}
return deck;
}
function nextCard(){
var k = deck.indexOf();
if( (k+1) <= deck.length){
return deck[k+1];
} else{
return deck[0];
}
}
function previousCard(){
var k = deck.indexOf();
if( (k-1) >= 0){
return deck[k-1];
} else{
return deck[(deck.length - 1)];
}
}
buildDeck();
return(
<View>
<Text>Cards</Text>
{renderCard(deck)}
<View style={styles.row}>
<Button
title='Next'
onPress={
nextCard()
}
/>
renderItem{renderMastery}
<Button
title='Previous'
onPress = {
previousCard()
}
/>
</View>
</View>
)
}
const styles= StyleSheet.create({
row: {
flexDirection: 'row',
flex: 1,
marginBottom: 1
},
})
export default CardScreen;

Categories

Resources