This post is about how to perform search operations in a list of items with color highlight in a simple approach. This approach is using a string method indexOf
.
Contents
- Sample Search component
- Basic page structure
- Search in post Title
- Lowercase
- Search in post Description
- Optimization
Sample SEARCH component
First, we are going to design a sample search component for basic understanding. In a search component there are 3 parts. Left side text, keyword part and the right side text. For this we need to use nested Text component.
export default function App() {
const SearchResultSampleComp = () => {
return (
<Text>
This is left side <Text style={{backgroundColor:"#FFC04C"}} >searchKeyword</Text>
<Text> and this is right side</Text>
</Text>
);
};
return (
<View style={styles.container}>
<SearchResultSampleComp/>
</View>
);
}
Yes, this is what we need to know.
The keyword index is 18 this is important to note and it is highlighted with color. Shall we start now?
Basic page structure
Lets start constructing the basic page with sample data. In this page we have search input and the post list using flatlist component.
sample data
// sample data
const list_post = [
{
id: '1',
description:
'JavaScript is a single-threaded, non-blocking, and asynchronous programming language. This means that it has only one execution thread, but it can handle asynchronous operations efficiently without blocking the execution of the entire program. This is achieved through a mechanism called the event loop.',
title:
'JavaScript s Single-Threaded Bliss: Because Who Needs Multithreading Anyway',
},
{
id: '2',
description:
'In our working time, sometimes we need to create some simple, light, quick components to render to any technology stacks. For example we build a screen loader component before js bundle back to expect users waiting',
title: 'Light weight (5k) JS framework to create Web Components',
},
{
id: '3',
description:
'Today i will be showing the easiest way to send push notifications to yourself using Cronus Monitoring and Alerting.We ll be using the npm package cronus-alert to send an alert for an event. We’ll then receive this alert on our mobile device by using the Cronus Mobile App.',
title: 'The easiest way to send mobile push notifications for developers',
},
{
id: '4',
description:
'In the vast landscape of frontend development, navigating the intricacies of state management can often feel like deciphering a complex narrative. Enter Redux, a steadfast storyteller in our coding adventures, unraveling the tale of centralised state management. ',
title: 'Navigating the React Redux toolkit as a Frontend developer',
},
{
id: '5',
description:
'In the world we live in today, data is like the puzzle pieces that fit together to reveal the bigger picture of success for businesses. Its the key ingredient, the secret sauce that companies use to make informed decisions and navigate the complexities of the digital era. Now, imagine you re in Hyderabad, a bustling city known for its tech scene, where the demand for skilled individuals in the field of data engineering is soaring high.',
title: 'Starting the Data Journey: Learning Azure Data Engineering',
},
];
the page
export default function App() {
const [searchText, setSearchText] = useState('');
const renderItem = ({ item }) => {
return (
<View style={styles.postItem}>
<Text numberOfLines={2} style={styles.title}>
{item.title}
</Text>
<Text numberOfLines={4} style={styles.desc}>
{item.description}
</Text>
</View>
);
};
return (
<View style={styles.container}>
<TextInput
style={styles.searchInput}
placeholder={'Search'}
value={searchText}
onChangeText={setSearchText}
/>
<FlatList
data={list_post}
renderItem={renderItem}
keyExtractor={(item, index) => '_listItem_' + index}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#eeffff',
paddingVertical: 10,
paddingHorizontal: 3,
},
searchInput: {
alignSelf: 'center',
width: '80%',
borderWidth: 0.5,
borderColor: 'grey',
marginBottom: 10,
paddingVertical: 7,
paddingHorizontal: 5,
borderRadius: 5,
},
desc: {
fontSize: 14,
color: '#303030',
},
title: {
color: 'black',
fontWeight: 'bold',
fontSize: 16,
marginBottom: 3,
},
postItem: {
marginTop: 5,
},
});
Search in post Title
We are using string indexOf
method to search in post title. Based on the index, the left side, the keyword and the right side parts can be separated.
const renderItem = ({ item }) => {
const indx = item.title.indexOf(searchText);
const length = searchText.length;
return (
<View style={styles.postItem}>
<Text numberOfLines={2} style={styles.title}>
{item.title.substr(0, indx)}
<Text style={{ backgroundColor: '#FFC04C' }}>
{item.title.substr(indx, length)}
</Text>
<Text>{item.title.substr(indx + length)}</Text>
</Text>
<Text numberOfLines={4} style={styles.desc}>
{item.description}
</Text>
</View>
);
};
here we're getting the index of search text and the length of it. By using string substr
method we can easily cut out the side parts and keyword separately. 0 to indx -> left side, indx to length -> keyword and indx+length to end -> right side.
Got it? additionally we have to add few if conditions as well.
const renderItem = ({ item }) => {
if (!searchText || searchText.trim().length < 1) {
return (
<View style={styles.postItem}>
<Text numberOfLines={2} style={styles.title}>
{item.title}
</Text>
<Text numberOfLines={4} style={styles.desc}>
{item.description}
</Text>
</View>
);
}
const indx = item.title.indexOf(searchText);
const length = searchText.length;
if (indx < 0) return null;
return (
<View style={styles.postItem}>
<Text numberOfLines={2} style={styles.title}>
{item.title.substr(0, indx)}
<Text style={{ backgroundColor: '#FFC04C' }}>
{item.title.substr(indx, length)}
</Text>
<Text>{item.title.substr(indx + length)}</Text>
</Text>
<Text numberOfLines={4} style={styles.desc}>
{item.description}
</Text>
</View>
);
};
Good, it is working fine.
Lowercase
Lets try searching one more time with the word React.
Wait, what? There is no item.
Did you get the point? javascript is case sensitive. So we have to change the case of both title and search keyword into lowercase since mostly users type in lowercase.
const renderItem = ({ item }) => {
. . .
const indx = item.title.toLowerCase().indexOf(searchText.toLowerCase());
. . .
};
Perfect.
Search in post Description
We're applying the same concept which we did before with few conditional rendering.
const renderItem = ({ item }) => {
if (!searchText || searchText.trim().length < 1) {
return (
<View style={styles.postItem}>
<Text numberOfLines={2} style={styles.title}>
{item.title}
</Text>
<Text numberOfLines={4} style={styles.desc}>
{item.description}
</Text>
</View>
);
}
const indx = item.title.toLowerCase().indexOf(searchText.toLowerCase());
const indx2 = item.description
.toLowerCase()
.indexOf(searchText.toLowerCase());
const length = searchText.length;
if (indx < 0 && indx2 < 0) return null;
return (
<View style={styles.postItem}>
{indx < 0 ? (
<Text numberOfLines={2} style={styles.title}>
{item.title}
</Text>
) : (
<Text numberOfLines={2} style={styles.title}>
{item.title.substr(0, indx)}
<Text style={{ backgroundColor: '#FFC04C' }}>
{item.title.substr(indx, length)}
</Text>
<Text>{item.title.substr(indx + length)}</Text>
</Text>
)}
{indx2 < 0 ? (
<Text numberOfLines={4} style={styles.desc}>
{item.description}
</Text>
) : (
<Text numberOfLines={4} style={styles.desc}>
{item.description.substr(0, indx2)}
<Text style={{ backgroundColor: '#FFC04C' }}>
{item.description.substr(indx2, length)}
</Text>
<Text>{item.description.substr(indx2 + length)}</Text>
</Text>
)}
</View>
);
};
Optimization
As of now it is working correctly but whenever user types a character the renderItem will be triggered and the lowercase method will be called for fields title,description and searchKeyword each and every time.
With few modifications we can bring the better than before version. Shall we move for optimizing?
The plan is, we are duplicating the fields title, description of array items and going to use a variable for searchKeyword.
var searchText2 = '';
export default function App() {
const [listPost2, setListPost2] = useState([]);
. . .
useEffect(() => {
const arr = list_post.map((ele) => ({
...ele,
title2: ele.title.toLowerCase(),
description2: ele.description.toLowerCase(),
}));
setListPost2(arr);
}, []);
const renderItem = ({ item }) => {
. . .
const indx = item.title2.indexOf(searchText2);
const indx2 = item.description2.indexOf(searchText2);
const length = searchText2.length;
. . .
};
return (
<View style={styles.container}>
<TextInput
style={styles.searchInput}
placeholder={'Search'}
value={searchText}
onChangeText={(txt) => {
searchText2 = txt.toLowerCase();
setSearchText(txt);
}}
/>
<FlatList
data={listPost2}
renderItem={renderItem}
keyExtractor={(item, index) => '_listItem_' + index}
/>
</View>
);
. . .
Here we are forming new array, with 2 new duplicate fields with lowercase. Since this is inside useEffect
it will be triggered only one time. And also for searchKeyword we are using an ordinary variable which holds lowercase value of the searchKeyword.
Done, hope this works fast and better than before.
Yes we made it, did we?
I hope, this post has some useful stuffs which will be helpful to you. Thank you for reading this, thank you for everything.
Full source code available here on GitHub
Tags: #react, #react-native, #javascript, #android, #ios, #web, #search-in-list, #array-filter
Top comments (0)