Search bar glitching out in React Native - javascript

I'm making a search bar that displays results live. I've managed to do it properly utilizing SearchBar from 'react-native-elements'. Firstly I had it written as a class component, but decided to rewrite it as a functional component. After rewriting it I'm encountering a bug where the keyboard closes after one letter as seen in the video here
Here is the code of the component
import React, { Component, useEffect, useState } from "react";
import { View, Text, FlatList, TextInput, ListItem } from "react-native";
import { SearchBar } from "react-native-elements";
import { Button } from 'react-native-paper'
import Header from "../navigation/Header";
export default function AktSelect() {
const [data, setData] = useState([])
const [value, setValue] = useState('')
const [akt, setAkt] = useState([])
useEffect(() => {
fetch("http://192.168.5.12:5000/aktprikaz", {
method: "get"
})
.then(res => res.json())
.then(res => setAkt(res));
}, []);
function renderSeparator() {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE"
}}
/>
);
}
function searchItems(text) {
const newData = akt.filter(item => {
const itemData = `${item.title.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setData(newData)
setValue(text)
}
function renderHeader() {
return (
<SearchBar
placeholder=" Type Here...Key word"
onChangeText={text => searchItems(text)}
value={value}
lightTheme={true}
/>
);
}
return (
<View
style={{
flex: 1,
width: "98%",
alignSelf: "center",
justifyContent: "center"
}}
>
<Header title='Pretraživanje aktivnosti' />
<FlatList
data={data}
renderItem={({ item }) => (
<View style={{flex: 1}}>
<Text style={{ padding: 10 }}>{item.title} </Text>
<View style={{flexDirection:'row'}}>
<Text style={{ padding: 10 }}>{item.start_time} </Text>
<Button style={{justifyContent: 'flex-end', alignContent: 'flex-end', width:'30%'}} mode='contained' onPress={() => console.log('hi')}>hi</Button>
</View>
</View>
)}
keyExtractor={item => item.id.toString()}
ItemSeparatorComponent={renderSeparator}
ListHeaderComponent={renderHeader}
/>
</View>
);
}
The old class component can be found here

Related

Cannot read property of 'navigate' of undefined

I am trying to make a stack navigator using reactstack navigation. When the button clicks, it appears on the detail screen only, the title of the page is detail. I am not yet to parsing data array to the next screen, it just tries to navigate the screen into the detail screen, and gets this error. I am new to react. Please help me solve this problem.
import React from 'react'
import {Button, StyleSheet, ScrollView, Text, View} from 'react-native'
import {useState, useEffect} from 'react'
import axios from 'axios'
const Item = ({id, user_id, title, onPress, navigation}) => {
return (
<View style={styles.container}>
<Text style={styles.text}>Id :{id}
</Text>
<Text style={styles.text}>User Id :{user_id}
</Text>
<Text style={styles.text}>Tittle :{title}
</Text>
<View style={styles.container}>
<Button onPress={() => navigation.navigate('Detail')} title='Detail'></Button>
</View>
<View style={styles.line}></View>
</View>
)
}
const Berita = () => {
const [users,
setUsers] = useState([]);
useEffect(() => {
getData();
}, []);
const selectItem = (item) => {
console.log('Selected item: ', item)
}
const getData = () => {
axios
.get('https://gorest.co.in/public/v1/posts')
.then(res => {
console.log('res: ', res);
setUsers(res.data.data);
})
}
return (
<ScrollView style={styles.container}>
{users.map(user => {
return <Item key={user.id} id={user.id} user_id={user.user_id} title={user.title}/>
})}
</ScrollView>
)
}
export default Berita
const styles = StyleSheet.create({
container: {
padding: 15
},
text: {
color: "black",
marginTop: 5,
fontStyle: 'italic',
fontSize: 18,
fontFamily: 'Arial'
},
line: {
height: 1,
backgroundColor: 'black',
marginVertical: 20
},
title: {
fontSize: 25,
fontWeight: 'bold',
textAlign: 'center',
color: "black"
},
tombol: {
padding: 10
}
})
This is the stack screen navigator code
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
const DetailBerita = () => {
return (
<Stack.Navigator >
<Stack.Screen
name='Berita'
component={Berita}
options={{
headerTitleAlign: 'center'
}}/>
<Stack.Screen
name="Detail"
component={Detail}
options={{
headerTitleAlign: 'center'
}}/>
</Stack.Navigator>
)
}
It appears that you are using Stack Navigators with different screen names, but you didn't send it. If possible, can you send that file, I would be able to help you a bit better. But from what I have I can try and explain how Stack navigation works. With this line of code:
navigation.navigate('Detail')
You specify that you want to navigate to the screen named "Detail", if you want to navigate to another screen then you can change it to the name of the screen. Let's say you want to navigate to your home screen, and its named "Home" in your Stack.Navigation component. Simply change your navigation to the following:
navigation.navigate('Home')
This is happening because the navigation prop is passed to the Berita component and you are destructuring the property in Item component not in Berita.
So the code should look like
...
const Berita = ({ navigation }) => {
// ...
return (
<ScrollView style={styles.container}>
{users.map(user => {
return (
<Item
key={user.id}
id={user.id}
user_id={user.user_id}
title={user.title}
navigation={navigation} // Pass navigation
/>
);
})}
</ScrollView>
);
};
Another way is - you can just use navigation in onPress (Berita) and pass down onPress to Item component
const Item = ({ id, user_id, title, onPress }) => {
return (
<View style={styles.container}>
<Text style={styles.text}>Id :{id}</Text>
<Text style={styles.text}>User Id :{user_id}</Text>
<Text style={styles.text}>Tittle :{title}</Text>
<View style={styles.container}>
<Button onPress={onPress} title="Detail" />
</View>
<View style={styles.line}></View>
</View>
);
};
const Berita = ({ navigation }) => {
const [users, setUsers] = useState([]);
useEffect(() => {
getData();
}, []);
const selectItem = item => {
console.log('Selected item: ', item);
};
const getData = () => {
axios.get('https://gorest.co.in/public/v1/posts').then(res => {
console.log('res: ', res);
setUsers(res.data.data);
});
};
return (
<ScrollView style={styles.container}>
{users.map(user => {
return (
<Item
key={user.id}
id={user.id}
user_id={user.user_id}
title={user.title}
onPress={() => navigation.navigate('Detail')}
/>
);
})}
</ScrollView>
);
};

React Native: Invalid hook calls

I am trying to get accustomed with React Native. Currently I have these nested FlatLists (where the first level displays a list of RenderedOrders, whereas these RenderedOrders themselves have a FlatList within them).
This is the main screen:
const ActiveScreen = () => {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
const [isLoadingApi, setLoadingApi] = useState(true);
const [orderData, setOrderData] = useState([])
/* Fetch currently taken orders */
useEffect(() => {
getTakenOrders()
.then((data) => setData(data))
.catch((error) => console.error(error))
.finally(() => setLoading(false));
}, []);
/* Fetch order info from API */
useEffect(() => {
fetch('https://alessandro-visualizr.herokuapp.com/api/orders/NEFACTURAT')
.then((response) => response.json())
.then((json) => setOrderData(json))
.catch((error) => console.error(error))
.finally(() => setLoadingApi(false));
}, []);
return (
<View style={{ flex: 1, padding: 24 }}>
{isLoading || isLoadingApi ? <ActivityIndicator/> : (
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (RenderedOrder(item, orderData)) }
/>
)}
</View>
);
}
export default ActiveScreen;
While this is the above-mentioned component:
import React, {useEffect, useState} from "react";
import {FlatList, Text, View} from "react-native";
import {removeTakenOrder} from "../screens/OrderScreen";
function RenderedOrder(orderId, orderData) {
const [triggered, setTriggered] = useState(true);
return (
<View
style={{ flex: 1}}
>
<View
style={{ fontSize: 20, borderRadius: 5, borderWidth: 1,
marginBottom: 10, padding: 10, backgroundColor: 'rgba(34, 139, 34, 0.75)', color: 'black',
flex: 1 }}
>
<Text
style={{ fontSize: 24 }}
>
#{orderId}
</Text>
<View
style={{ alignItems: 'flex-end' }}
>
<Text
style={{ fontWeight: 'bold', color: 'red', fontSize: 20 }}
onPress={() => removeTakenOrder(orderId)
.then(() => alert("Order #" + orderId + " has been removed"))
}
>
X
</Text>
</View>
</View>
{true &&
<FlatList
data={orderData.filter((order) => (order.orderId === orderId))[0].products}
keyExtractor={({ id }, index) => id}
listKey = {orderId}
renderItem={({ item }) => (
<View>
<Text
style={{ fontSize: 18, padding: 5 }}
>
- {item.name}
<Text style={{ fontWeight: 'bold' }}> x{item.quantity} </Text>
</Text>
</View>
)}
/>
}
</View>
);
}
export default RenderedOrder;
However, when running this example I am confronted with this issue (due to RenderedOrder's state declaration):
Invalid hook call. Hooks can only be called inside the body of a function component.
I understand that in React, states can only be used within function and not class components. However I admit the differences between these two are not that clear to me. Am I commiting a mistake here?
You are using RenderedOrder as function instead of a functional component :
Change this:
renderItem={({ item }) => (RenderedOrder(item, orderData)) }
To this:
renderItem={({ item }) => <RenderedOrder item={item} orderData={orderData} /> }

When i want to delete one item in my list, everything gets deleted Expo, React Native

This is my app.js
the main body of my app.
...
import React, { useState } from "react";
import {
StyleSheet,
Text,
View,
Button,
TextInput,
FlatList,
} from "react-native";
import GoalItem from "./components/GoalItem";
import GoalInput from "./components/GoalInput";
export default function App() {
const [lifeGoals, setLifeGoals] = useState([]);
const addGoalHandler = (goalTitle) => {
setLifeGoals((currentGoals) => [
...currentGoals,
{ key: Math.random().toString(), value: goalTitle },
]);
};
const removeGoalHandler = (goalId) => {
setLifeGoals((currentGoals) => {
return currentGoals.filter((goal) => goal.id !== goalId);
});
};
return (
<View style={styles.Screen}>
<GoalInput onAddGoal={addGoalHandler} />
<FlatList
keyExtractor={(item, index) => item.id}
data={lifeGoals}
renderItem={(itemData) => (
<GoalItem
id={itemData.item.id}
onDelete={removeGoalHandler}
title={itemData.item.value}
/>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
Screen: {
padding: 50,
},
});
...
This is my GoalItem which houses my list
...
import React from "react";
import { StyleSheet, View, Text, TouchableOpacity } from "react-native";
const GoalItem = (props) => {
return (
<TouchableOpacity onPress={props.onDelete.bind(this, props.id)}>
<View style={styles.ListItem}>
<Text>{props.title}</Text>
</View>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
ListItem: {
padding: 10,
marginVertical: 10,
backgroundColor: "#CCFFFF",
borderRadius: 15,
},
});
export default GoalItem;
...
This is my GoalInput which handles the userinput and appending onto the list
...
import React, { useState } from "react";
import { View, TextInput, Button, Stylesheet, StyleSheet } from "react-native";
const GoalInput = (props) => {
const [enteredGoal, setEnteredGoal] = useState("");
const InputGoalHandler = (enteredText) => {
setEnteredGoal(enteredText);
};
return (
<View style={styles.inputContainer}>
<TextInput
placeholder="Enter Task Here"
style={styles.InputBox}
onChangeText={InputGoalHandler}
value={enteredGoal}
/>
<Button title="add" onPress={props.onAddGoal.bind(this, enteredGoal)} />
</View>
);
};
const styles = StyleSheet.create({
InputBox: {
borderColor: "black",
borderWidth: 0,
padding: 10,
width: "80%",
},
inputContainer: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
});
export default GoalInput;
...
I believe that the key might be the issue but i'm really not sure. What's supposed to happen is that when you click on an item in the list, it should be deleted, however it's deleting my whole list. How do i solve this?
const removeGoalHandler = (goalId) => {
setLifeGoals(lifeGoals.filter((m) => m.id !== goalId.id));
};
<FlatList
keyExtractor={(item) => item.id}
data={lifeGoals}
renderItem={(itemData) => (
<GoalItem
onDelete={removeGoalHandler}
title={itemData.item.value}
/>
)}
/>
const GoalItem = ({onDelete, title}) => {
return (
<TouchableOpacity onPress={onDelete}>
<View style={styles.ListItem}>
<Text>{title}</Text>
</View>
</TouchableOpacity>
);
};
try this

Not sure how to remove this FlatList from displaying by default on screen

Currently, this - is how the SearchBar and FlatList is showing up on the screen. Upon clicking on the SearchBar and typing one of the list components, it shows up this- way. I want the FlatList to only appear when I click on the SearchBar. How do I implement this in the app? Something like a dropdown search bar...
import React from 'react';
import { View, Text, FlatList, ActivityIndicator, StyleSheet } from 'react-native';
import { SearchBar } from 'react-native-elements';
import { Button, Menu, Divider, Provider, TextInput } from 'react-native-paper';
const restaurantList = [
{
type: 'Italian',
name: 'DiMaggio'
},
{
type: 'Greek',
name: 'Athena'
}
];
export default class App extends React.Component {
static navigationOptions = {
title: 'Search for Restaurants'
};
constructor (props) {
super(props);
this.state = {
loading: false,
data: restaurantList,
error: null,
value: '',
};
this.arrayholder = [];
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '14%'
}}
/>
);
};
searchFilterFunction = text => {
this.setState({
value: text
});
const newData = restaurantList.filter(item => {
console.log(item.type)
const itemData = `${item.name.toUpperCase()} ${item.type.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.includes(textData);
});
this.setState({
data: newData
});
};
renderHeader = () => {
return (
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)}
/>
);
};
render () {
if (this.state.loading) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
);
} else {
return (
<Provider>
<View
style={{
paddingTop: 50,
flexDirection: 'row',
justifyContent: 'center',
}}>
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => `${index}`}
extraData={this.state}
data={this.state.data}
renderItem={({ item }) => (
<Text>{item.name} {item.type}</Text>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
</View>
<View style={styles.container}>
<TextInput />
</View>
</Provider>
);
}
}
}
Try this way
this.state = {
searchClicked: false
};
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)}
onFocus={() => this.setState({searchClicked: true})}
onBlur={() => this.setState({searchClicked: false})}
/>
<View>{this.renderHeader()}</View>
{this.state.searchClicked && <FlatList
keyExtractor={(item, index) => `${index}`}
extraData={this.state}
data={this.state.data}
renderItem={({ item }) => (
<Text>{item.name} {item.type}</Text>
)}
ItemSeparatorComponent={this.renderSeparator}
// ListHeaderComponent={this.renderHeader} <—- Remove from here —->
/>}
In case #Lakhani reply doesn't satisfy your question, I have another suggestion for you.
Your SearchBar should contain a TextInput. You can use onFocus and onBlur props to capture event you click on SearchBar or leave it.
...
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)}
onFocus={()=>this.setState({showList: true})} // <---
onBlur={()=>this.setState({showList: false})} // <---
/>
...
render() {
return (
...
{
this.state.showList && <FlatList ... />
}
)
}

Can't find variable itemData in react-native

Code :
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, TextInput, ScrollView, FlatList } from 'react-native';
import GoalItem from './components/GoalItem';
export default function App() {
const [enteredGoal, setEnteredGoal] = useState('');
const [courseGoals, setCourseGoals] = useState([]);
const goalInputHandler = (enteredText) => {
setEnteredGoal(enteredText);
};
const addGoalHandler = () => {
//console.log(enteredGoal);
setCourseGoals(currentGoals => [...currentGoals, { id: Math.random().toString(), value: enteredGoal }]);
};
return (
<View style={styles.screen}>
<View style={styles.inputContainer}>
<TextInput placeholder="Course Goal" style={styles.input}
onChangeText={goalInputHandler} value={enteredGoal} />
<Button title="Add" onPress={addGoalHandler} />
</View>
<FlatList keyExtractor={(item, index) => item.id} data={courseGoals}
renderItem={itemData => <GoalItem title={itemData.item.value} />}
/>
</View>
);
}
const styles = StyleSheet.create({
screen: {
padding: 50
},
inputContainer: {
flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'
},
input: {
width: '70%', borderBottomColor: 'black', borderWidth: 1, padding: 10
},
});
GoalItem Components :
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const GoalItem = props => {
return (
<View style={styles.listItem}>
<Text>{props.title}</Text>
</View>
);
};
const styles = StyleSheet.create({
listItem: {
padding: 10, backgroundColor: '#ccc', borderColor: 'black', borderWidth: 1, marginVertical: 10
}
});
export default GoalItem;
Error : Below is the code, please check Can't find variable itemData
in react-native
Pls i am a newbie in react-native i just got for about two hours. Any
help would be appreciated. Thanks in advance. Look into the code and share some advice so that the code works well..
Thanks :)
It should be
<FlatList keyExtractor={(item, index) => item.id}
data={courseGoals}
renderItem={(itemData) => <GoalItem title={itemData.item.value} }/>
Or
<FlatList keyExtractor={(item, index) => item.id}
data={courseGoals}
renderItem={({item}) => <GoalItem title={item.value} }/>
it should be like this :
<FlatList
data={courseGoals}
renderItem={itemData => (
<View style={styles.listItem}>
<Text>{itemData.item}</Text>
</View>
)}
/>

Categories