I'm getting my data from an SQLite database and showing the data when the tab is focused. The problem is that the Scrollview displaying the data is being duplicated whenever I move to another tab. How do I prevent this from happening?
componentDidMount() {
this._subscribe = this.props.navigation.addListener('didFocus', () => {
this.retrieveSavedCards();
});
}
This is how I'm retrieving the data
retrieveSavedCards(){
db.transaction(
tx => {
tx.executeSql('select * from MyScannedCards', [], (trans, result) => {
var len = result.rows.length;
for (i=0;i<len;i++){
cardDetails = result.rows._array[i];
this.setState({ cardholders: this.state.cardholders.concat(cardDetails) })
}
});
}
);
}
This is my scrollview and how the data is supposed to be displayed:
<ScrollView>
{
this.state.cardholders.map((l, i) => (
<ListItem
key={i}
leftAvatar={{ source: { uri: this.state.baseUrl+l.avatar } }}
title={l.cardholderfirstname + " " + l.cardholderlastname}
subtitle="Your company"
onPress={() => {
this.toggleModal();
}}
/>
))
}
</ScrollView>
This is my state:
this.state = {
cardholders: [
],
baseUrl: "http://myurl.com"
};
You will have to unmount the didFocus event listener.
As mentioned here : https://reactnavigation.org/docs/en/status-bar.html#tabnavigator
componentWillUnmount() {
this._subscribe.remove();
}
Bit of a hack, but I couldn't figure out how to stop the scrollview from duplicating so instead I made the scrollview stop displaying an object already in state.
In my for loop:
for (i=0;i<len;i++){
cardDetails = result.rows._array[i];
console.log(cardDetails.id)
this.addUser(cardDetails);
}
And then additional functionality to check for duplicates and update state if something new is found.
userExists(cardDetails) {
return this.state.cardholders.some(function(el) {
return el.id === cardDetails.id;
});
}
addUser(cardDetails) {
if (this.userExists(cardDetails)) {
console.log("Skipping")
return false;
}
this.setState({ cardholders: this.state.cardholders.concat(cardDetails) })
console.log("Adding")
return true;
}
Related
Right now I have a navbar at the bottom of my screen that has a link to a user's notifications. When I click the notification button the first time it works, I can see the notification list ("PractNotificationIndex"). From there, if I click a notification, it takes me to the user's profile to send that notification. Now when I'm on that profile screen, there's still a navbar at the bottom the user can use. If I click on the notification button again, I can repeat the process of going to the user's profile.
NavigationBar.js:
async componentDidMount(){
console.log("NAV BAR MOUNTED")
//const initialNotificationsList = this.getInitialNotificationList()
const patientEmail = this.props.extraData.user
const getInitialNotificationList = await axios
.post(
"http://192.168.2.99:3001/graphql",
{
"query": `query getNotifications($email: String!) {
getNotifications(email: $email) {
date
practEmail
patientEmail
timeStart
timeEnd
accepted
client
}
}`,
"variables": {
"email": patientEmail
}
},
)
const initialNotificationList = getInitialNotificationList.data.data.getNotifications
//console.log("INITIAL NOTI LIST", initialNotificationList)
var notificationsConcat = this.state.notifications.concat(initialNotificationList)
//console.log("NOTI CONCAT", notificationsConcat)
this.setState({notifications:notificationsConcat})
// subscribe to the notifications events endpoint
// const options = {
// method: "GET",
// timeout: 0,
// body: this.props.practData
// }
const practEmail = this.props.extraData.user
const options = { headers: { practEmail: practEmail } }
console.log("PRACT EMAIL NOTI NAV BAR", this.props.extraData)
const events = new EventSource("http://192.168.2.99:3001/pract_notifications", options)
events.addEventListener("error", (event) => {
if (event.type === "error") {
console.error("Connection error:", event.message);
} else if (event.type === "exception") {
console.error("Error:", event.message, event.error);
}
})
events.addEventListener("close", (event) => {
console.log("CLOSED SSE CONNECTION!!")
// clear the state because it will repopulate upon reconnection
events.close()
this.setState({notifications: []})
})
this.setState({listening:true})
return events
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.groupContainer}
{/* NAVIGATE TO NOTIFICATION LIST HERE!*/}
onPress={() => this.props.navigation.push("PractNotificationIndex", {notifications: this.state.notifications})}
>
<Image source={NavProfile} />
<Text style={styles.navText}>{this.state.notifications.length}</Text>
</TouchableOpacity>
</View>
);
}
}
But, now once I'm on the profile and click the notifications button, it reveals the notifications list, but it's not rerendering it. The log messages that are supposed to print out don't get printed, but the component still gets displayed fine. And when I click a notification nothing happens immediately. After like 10 minutes it will navigate where it's supposed to.
PractNotificationIndex.js
class PractNotificationIndex extends Component {
constructor(props) {
super(props);
this.state = {
//notifications: this.props.route.params.notifications,
events: null,
notifications: [],
listening: false,
user: {}
}
this.handleStateChange = this.handleStateChange.bind(this)
console.log("NOTI INDEX PROPS", this.props)
}
componentDidMount(){
const initialNotificationList = this.props.route.params.notifications
var notificationsConcat = this.state.notifications.concat(initialNotificationList)
this.setState({notifications:notificationsConcat})
const practEmail = this.props.extraData.user
const options = { headers: { practEmail: practEmail } }
const events = new EventSource("https://**.com/pract_notifications", options)
events.addEventListener("error", (event) => {
if (event.type === "error") {
console.error("Connection error:", event.message);
} else if (event.type === "exception") {
console.error("Error:", event.message, event.error);
}
})
events.addEventListener("close", (event) => {
console.log("CLOSED INDEX SSE CONNECTION!!")
// clear the state because it will repopulate upon reconnection
events.close()
this.setState({notifications: []})
})
this.setState({listening:true})
}
render() {
// use a map to iterate through the results array so they can be displayed in the results
return (
<View style={styles.container}>
{
this.state.notifications.length > 0 ?
<ScrollView>
{this.state.notifications.map((noti, key) =>
<PractNotification key={key} navigation={this.props.navigation} extraData={{notifications: noti}}/>
)}
</ScrollView> : <Text> No new Notifications </Text>}
</View>
);
}
}
});
export default PractNotificationIndex;
Is some navigation loop happening that's causing this issue? I'm really confused as to why it's happening, I just want to be able to click the navbar from any screen
I have a list of items and I'm using useInfiniteQuery for pagination stuff,
So I have a case where I can edit Item info then re-fetch the list again to get the updated list of items,
So I'm trying to re-fetch the list using
refetchPage() FC it works when I'm on the first page 1
but
current behavior:
when I scroll down to page 2 "last page at this moment." then update the item when
using queryClient.refetchQueries
it replaces the prev data with the re-fetched data on the current page.
await queryClient.refetchQueries(['getUsualOrders'], {
stale: true,
});
using refetch().
refetchUsualOrderList({
refetchPage: (page, index) => {
return index === 0;
},
});
it replaces the prev data with current page data without the updated data
Actually, it sends a request for the next page "that doesn't exist"
So how can i re-fetch the data and keep the previous data?
Code
Hook
export const useUsualOrders = ({lang, pageNumber = 1, token}) => {
return useInfiniteQuery(
['getUsualOrders'],
() => getUsualOrders({lang, pageNumber, token}),
{
getNextPageParam: lastPage => {
if (lastPage.next !== null) {
return lastPage.next;
}
return undefined;
},
},
);
};
UI
const [currentPageNumber, setCurrentPageNumber] = useState(1);
const {
data: usualOrdersList,
hasNextPage,
fetchNextPage,
isFetchingNextPage,
refetch: refetchUsualOrderList,
} = useUsualOrders({
lang,
token: currentUserInfo?.token,
pageNumber: currentPageNumber,
});
const loadMore = () => {
if (hasNextPage) {
setCurrentPageNumber(prev => prev + 1);
fetchNextPage();
}
};
const onRefetch = ()=>{
refetchUsualOrderList({
refetchPage: (page, index) => {
return index === 0;
},
});
}
<FlatList
showsVerticalScrollIndicator={false}
data={usualOrdersList.pages.map(page => page.results).flat()}
renderItem={renderModelItems}
keyExtractor={item => item.id}
onEndReached={loadMore}
onEndReachedThreshold={0.3}
// refreshControl={
// <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
// }
style={{
backgroundColor: secondary_bg_color,
}}
contentContainerStyle={[
styles.modelList,
{
backgroundColor: secondary_bg_color,
paddingHorizontal: PADDING_HORIZONTAL.SMALL,
},
]}
ListFooterComponent={
isFetchingNextPage ? (
<ActivityIndicator color={buttonBgColor} />
) : null
}
/>
response body
When I render my flatlist, it seems to duplicate items inside it (feedCache has one index and it will render the data for this index twice). Here's the code for the flatlist:
const FeedBody = React.memo(() => {
return (
<FlatList
data={feedCache}
renderItem={({ item }) => {
return (
<FeedPost
item={item}
/>
)
}}
keyExtractor={item => item.id}
/>
)
})
return (
<>
{feedLoaded && feedCache && feedReturnCache
? <FeedBody />
: <AppLoading />
}
</>
)
At the top of the document, in the useEffect, I fetch data from an API and write parts to feedCache and feedReturnCache. Once this completes feedLoaded is set to true and the feed body is supposedly rendered. Despite this, I'm convinced the FeedBody component is still re-rendering due to state updates. This causes duplication of items inside the flatlist. Is there a way to fix/prevent this?
Any help would be appreciated, thanks.
(useEffect code)
const [feedLoaded, setFeedLoaded] = useState(false)
const [feedCache, setFeedCache] = useState(null)
const [feedReturnCache, setFeedReturnCache] = useState(null)
useEffect(() => {
feedMounted = true
server("POST", "/content/feed", {
token: user.token,
cachePresent: false,
metric: "new"
}, (data, http, error) => {
if (!error) {
const toBeStatefulFeedReturnCache = new Array()
for (let i = 0; i < data.length; i++) {
toBeStatefulFeedReturnCache.push({
id: data[i].id,
read: false
})
if (i + 1 === data.length) {
if (feedMounted) {
setFeedCache(data)
setFeedReturnCache(toBeStatefulFeedReturnCache)
setFeedLoaded(true)
}
}
}
} else {
throw error
}
})
return () => {
feedMounted = false
}
}, [])
Try to fix duplication in array with set
I have a SearchBar and a simple FlatList. My logic for search filter is working fine but that is fine for simple search.
Example:
If my FlatList has three items
Visiting hour.
He knew the visit hour.
visit and hour.
In my SearchBar if i search "visit h" it will render only item 2 -> 2. He knew the visit hour.
I want it to render all 3 items when i search "visit h"
My Search filter should look for every item that includes "visit" and "h".
It should also include "visit" in "visiting"
How can i capture this type of filter? Is there any js Library that can be used? Any efficient way to execute this search filter?
My current code is below:
export default class HomeComponent extends Component {
constructor(props) {
super(props)
this.state = {
isLoading: true,
notifications: [],
query: '',
temp: []
}
};
componentDidMount() {
fetch('https://140xya6a67.execute-api.ap-southeast-1.amazonaws.com/dev/', {
method: 'GET',
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
notifications: responseJson,
notificationRead: false,
temp: responseJson,
})
})
};
goToDetails() {
return this.props.navigation.navigate(Details);
}
renderItem({item}) {
return <NotificationItem item={item}
onPress={() => {this.goToDetails()}}/>
}
handleSearch(text) {
const newData = _.filter(this.state.temp, (item) => {
const itemData = item.Desc ? item.Desc.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
notifications: newData,
query: text,
});
}
renderContent() {
let {notifications} = this.state;
return (
<View>
<SearchBar placeholder='type here...' lightTheme round value={this.state.query}
onChangeText={(text) => {this.handleSearch(text)}}/>
<FlatList
keyExtractor={(item, id) => item.id}
data={notifications}
renderItem={this.renderItem.bind(this)}
/>
</View>
);
}
render() {
let {fill, container} = styles;
return (
<View style={[fill, container]}>
{this.renderContent()}
</View>
);
}
}
You are describing full-text search, or even fuzzy search.
If you have a small list of static data, you can do it purely on frontend during run time with library like fuse.js.
For dynamic data, you need a backend to tokenize and prepare the data beforehand. Frontend then just send what the user has typed, and get feed the search result from backend.
You can build that yourself if you use a modern RDBMS like PostgreSQL or MSSQL. Or use services or tools more purposefully built for this problem, like algolia or Elasticsearch.
You can write simple filter of your own, like below (not tested):
handleSearch(text) {
if (!text || text.length === 0) {
this.setState({
notifications: this.state.temp,
query: text,
});
return;
}
const newData = _.filter(this.state.temp, item => {
const itemData = item.Desc ? item.Desc.toUpperCase() : ''.toUpperCase();
const textParts = text.toUpperCase().split(' ');
let shouldInclude = true;
for (let i = 0; i < textParts.length; i++) {
const part = textParts[i];
shouldInclude = shouldInclude && (itemData.indexOf(part) > -1);
if (!shouldInclude) {
return false;
}
}
return true;
});
this.setState({
notifications: newData,
query: text,
});
}
I am trying to search through a flatlist based on a search bar text. The problem I am running into is that when the user mistypes...say they wanted to type "burger" but typed "burget" by mistake then it returns nothing as it should. When the user deletes the "t" then it should re-render the flatlist again with the last text matching the "burge" part.
note: using react-native-elements search bar which allows me to call the text with just e or event.
What I have so far in the Main.js file:
searchText = (e) => {
let text = e.toLowerCase();
let trucks = this.state.data;
// search by food truck name
let filteredName = trucks.filter((truck) => {
return truck.name.toLowerCase().match(text);
});
// if no match and text is empty
if(!text || text === '') {
console.log('change state');
this.setState({
data: initial
});
}
// if no name matches to text output
else if(!Array.isArray(filteredName) && !filteredName.length) {
console.log("not name");
this.setState({
data: [],
});
}
// if name matches then display
else if(Array.isArray(filteredName)) {
console.log('Name');
this.setState({
data: filteredName,
});
}
};
<View style={styles.container}>
<SearchBar
round
lightTheme
containerStyle={styles.search}
ref="search"
textInputRef="searchText"
onChangeText={this.searchText.bind(this)}
placeholder='Search by Truck Name...'
/>
<TruckList getTruck={(truck) => this.setTruck(truck)} truckScreen={this.truckScreen} data={this.state.data}/>
</View>
then the TruckList.JS:
export default class TruckList extends Component {
// rendering truck screen
renderTruckScreen = (item) => {
this.props.truckScreen();
this.props.getTruck(item);
}
render() {
return(
<List style={styles.list}>
<FlatList
data={this.props.data}
renderItem={({ item }) => (
<ListItem
roundAvatar
avatar={{uri: item.pic1}}
avatarStyle={styles.avatar}
title={item.name}
titleStyle={styles.title}
subtitle={
<View style={styles.subtitleView}>
<Text style={styles.subtitleFood}>{item.food}</Text>
<View style={styles.subtitleInfo}>
<Icon
name="favorite"
size={20}
color={"#f44336"}
style={styles.subtitleFavorite}
/>
<Text style={styles.subtitleFavoriteText}>{item.favorited} favorited</Text>
</View>
</View>
}
onPress={() => this.renderTruckScreen(item)}
/>
)}
keyExtractor={(item) => item.uid}
ListFooterComponent={this.footer}
/>
</List>
)
}
}
I have tried a few other ways to no avail. Also the only solutions I have seen working for React Native are with ListView which will be depreciated in time. So I am trying to do this with the new FlatList Component.
Thanks for your help!
I came across this same issue today when trying to implement a filter / search function on the new FlatList component. This is how I managed to solve it:
By creating another item in the state of the parent component called noData, you can set that to true when there are no results that match your search and then render your FlatList conditionally.
My implementation is slightly different to yours, but if I had to adjust your code it would look something like this:
Searchtext function:
searchText = (e) => {
let text = e.toLowerCase()
let trucks = this.state.data
let filteredName = trucks.filter((item) => {
return item.name.toLowerCase().match(text)
})
if (!text || text === '') {
this.setState({
data: initial
})
} else if (!Array.isArray(filteredName) && !filteredName.length) {
// set no data flag to true so as to render flatlist conditionally
this.setState({
noData: true
})
} else if (Array.isArray(filteredName)) {
this.setState({
noData: false,
data: filteredName
})
}
}
Then pass the noData bool to your TruckList component:
<TruckList getTruck={(truck) => this.setTruck(truck)}
truckScreen={this.truckScreen} data={this.state.data} noData={this.state.noData}/>
Then render your FlatList in the TruckList component only if there are results:
<List style={styles.list}>
{this.props.noData ? <Text>NoData</Text> : <FlatList {...} />}
</List>
That should then take care of handling user typing errors - as it will re-render the flatlist as soon as there are no results, and will remember the previous search state when you remove the typing error..
Let me know if that helps!
For a useful in-memory search you should keep initial data seperately.
I have more simple solution for this.
This solution for in-memory search on FlatList's data and uses it String.prototype.includes() method to search substring.
You can find full source code of this component in this gist;
https://gist.github.com/metehansenol/46d065b132dd8916159910d5e9586058
My initial state;
this.state = {
searchText: "",
data: [],
filteredData: []
};
My SearchBar component (it comes from react-native-elements package);
<SearchBar
round={true}
lightTheme={true}
placeholder="Search..."
autoCapitalize='none'
autoCorrect={false}
onChangeText={this.search}
value={this.state.searchText}
/>
My search method;
search = (searchText) => {
this.setState({searchText: searchText});
let filteredData = this.state.data.filter(function (item) {
return item.description.includes(searchText);
});
this.setState({filteredData: filteredData});
};
And last my FlatList's DataSource expression;
<FlatList
data={this.state.filteredData && this.state.filteredData.length > 0 ? this.state.filteredData : this.state.data}
keyExtractor={(item) => `item-${item.id}`}
renderItem={({item}) => <ListItem
id={item.id}
code={item.code}
description={item.description}
/>}
/>
Happy coding...
Update:
This blog can help you better understand the searching in a FlatList.
FYI:
If you have huge online data then you can also use algolia.
I adjusted the above code for me in order to make it work properly. The reason is that when user removes the last wrong character, code search this new string from a previous search list (state) which does not contain all objects, although it had to search from a full list available. So, I have two list now. One contains full list of objects and second contains only rendered list of objects which is changing upon search.
handleSearchInput(e){
let text = e.toLowerCase()
let fullList = this.state.fullListData;
let filteredList = fullList.filter((item) => { // search from a full list, and not from a previous search results list
if(item.guest.fullname.toLowerCase().match(text))
return item;
})
if (!text || text === '') {
this.setState({
renderedListData: fullList,
noData:false,
})
} else if (!filteredList.length) {
// set no data flag to true so as to render flatlist conditionally
this.setState({
noData: true
})
}
else if (Array.isArray(filteredList)) {
this.setState({
noData: false,
renderedListData: filteredList
})
}
}
Make Search Bar Filter for List View Data in React Native
For Real-Time Searching in List View using Search Bar Filter
We will load the list from the network call and then show it to the user.
The user can search the data by entering the text in TextInput.
After inserting the text SearchFilterFunction will be called We will
compare the list data with the inserted data and will make a new Data
source.
We will update the data source attached to the ListView.
It will re-render the list and the user will be able to see the
filtered data.
//This is an example code to Add Search Bar Filter on Listview//
import React, { Component } from 'react';
//import react in our code.
import {
Text,
StyleSheet,
View,
FlatList,
TextInput,
ActivityIndicator,
Alert,
} from 'react-native';
//import all the components we are going to use.
export default class App extends Component {
constructor(props) {
super(props);
//setting default state
this.state = { isLoading: true, text: '' };
this.arrayholder = [];
}
componentDidMount() {
return fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(responseJson => {
this.setState(
{
isLoading: false,
dataSource: responseJson
},
function() {
this.arrayholder = responseJson;
}
);
})
.catch(error => {
console.error(error);
});
}
SearchFilterFunction(text) {
//passing the inserted text in textinput
const newData = this.arrayholder.filter(function(item) {
//applying filter for the inserted text in search bar
const itemData = item.title ? item.title.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
//setting the filtered newData on datasource
//After setting the data it will automatically re-render the view
dataSource: newData,
text: text,
});
}
ListViewItemSeparator = () => {
//Item sparator view
return (
<View
style={{
height: 0.3,
width: '90%',
backgroundColor: '#080808',
}}
/>
);
};
render() {
if (this.state.isLoading) {
//Loading View while data is loading
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<ActivityIndicator />
</View>
);
}
return (
//ListView to show with textinput used as search bar
<View style={styles.viewStyle}>
<TextInput
style={styles.textInputStyle}
onChangeText={text => this.SearchFilterFunction(text)}
value={this.state.text}
underlineColorAndroid="transparent"
placeholder="Search Here"
/>
<FlatList
data={this.state.dataSource}
ItemSeparatorComponent={this.ListViewItemSeparator}
renderItem={({ item }) => (
<Text style={styles.textStyle}>{item.title}</Text>
)}
enableEmptySections={true}
style={{ marginTop: 10 }}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
viewStyle: {
justifyContent: 'center',
flex: 1,
marginTop: 40,
padding: 16,
},
textStyle: {
padding: 10,
},
textInputStyle: {
height: 40,
borderWidth: 1,
paddingLeft: 10,
borderColor: '#009688',
backgroundColor: '#FFFFFF',
},
});
Click Hear for more idea
Here is my solution:
You need to have a backup of your data
this.state = {
data: [],
backup: []
}
on search method
search = txt => {
let text = txt.toLowerCase()
let tracks = this.state.backup
let filterTracks = tracks.filter(item => {
if(item.name.toLowerCase().match(text)) {
return item
}
})
this.setState({ data: filterTracks })
}
Explanation: when calling setState on your data it will changed to current state and cannot be changed again.
So backup data will handle to filter your data.
ref - https://medium.freecodecamp.org/how-to-build-a-react-native-flatlist-with-realtime-searching-ability-81ad100f6699
constructor(props) {
super(props);
this.state = {
data: [],
value: ""
};
this.arrayholder = [];
}
Next fetching data :-
_fetchdata = async () => {
const response = await fetch("https://randomuser.me/api?results=10");
const json = await response.json();
this.setState({ data: json.results });
this.arrayholder = json.results;
};
Next define searchFilterFunction :-
searchFilterFunction = text => {
this.setState({
value: text
});
const newData = this.arrayholder.filter(item => {
const itemData = item.email.toLowerCase();
const textData = text.toLowerCase();
return itemData.indexOf(textData) > -1;
});
this.setState({ data: newData });
};
rendering searchView:-
<TextInput
style={{ height: 40, borderColor: "gray", borderWidth: 1 }}
onChangeText={text => this.searchFilterFunction(text)}
/>
Don't forget to import TextInput from "react-native";
You can Search your data by following these steps :
<TextInput onChangeText={(text) => searchData(text)} value={input} />
***Please Note *searchData is my function whom I passing a text prop***
const searchData = (text) => {
const newData = restaurantsData.filter((item) => {
return item.title.search(text) > -1;
});
setRestaurantsData(newData);
setInput(text);
};
Note RestaurantsData is my data array
FYI : data is the subtext to be searched, this is a basic search implemented as the data to be searched is looked into every list item of an array which is a copy of the actual array/array of objects and finally its state is set whether match found or not between 0 to (actualArray.length-1) and the temporary arrayData is rendered if there is at least one match else actualArray is rendered
implementSearch(data) {
temp = [];
var count = 0;
var searchData = data.toUpperCase();
var arr = this.state.personDetail;
for (var i = 0; i < arr.length; i++) {
var actualData = arr[i].name.toUpperCase();
if (actualData.includes(searchData)) {
temp.push(arr[i]);
count++;
}
}
this.setState({
tempArray: temp,
matches: count,
searchValue: data
});
}
Hope this helps
My search method; from #metehan-senol
search = (searchText) => {
this.setState({searchText: searchText});
let filteredData = this.state.data.filter(function (item) {
return item.description.includes(searchText);
});
this.setState({filteredData: filteredData});
};
the search method of could be simplify and Eslint proof like so
search = (searchText) => {
const searched = searchText.toLowerCase();
this.setState(prevState => ({
searchText: searched,
filteredData: prevState.data.filter(item =>
item.description.toLowerCase().includes(searched)
),
}));
};
Do filter by applying
let filterData= data.filter((item) => {
return item.name.toLowerCase().match(text)
})
if (!text || text === '') {
this.setState({
datasource: initial
})
} else if (!Array.isArray(filterData) && !filterData.length) {
// set no data flag to true so as to render flatlist conditionally
this.setState({
noData: true
})
} else if (Array.isArray(filterData)) {
this.setState({
noData: false,`enter code here`
dataSource: filterData
})`enter code here`
}
This is not the best solution in terms of performance, but if you do not have a large amount of data, then feel free to use this function:
searchFilter () {
return this.props.data.filter((item) => {
const regex = new RegExp(this.state.searchInput, "gi")
return item.label.match(regex);
})
}
And then in your FlatList component:
<FlatList
data={this.searchFilter()}
renderItem={this.renderItem}
keyExtractor={(item) => item.value}
/>
const SearchUser = (e) =>{
console.log(e)
const setProject = Project.filter(item => item.name.toLowerCase().includes(e.toLowerCase()) )
console.log(setProject)
setfetch(setProject)
}