Search Filter or Search In List React Native
Tags: javascript, react, reactnative, android
Published: 2024-02-01 13:25:20

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>
  );
}

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivlgafv2800v19t86clr.png)

Yes, this is what we need to know. 

The keyword index is <u>18</u> 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,
  },
});

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qg9vm9hfvpe3sw7yiv5q.png)

**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>
    );
  };


```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bi5zmd3a6x130di6oz0v.png)

Good, it is working fine. 

**Lowercase**

Lets try searching one more time with the word <u>React</u>. 

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());   
. . .
};

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tai2ctv1izs51j1b04lq.png)

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>
    );
  };


```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6wh4foros6fun0rrwxp.png)

**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>
  );
 . . . 

```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c8ervbjqnep1pd1yjahe.png)

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 the lowercase value of searchKeyword. 

Done, hope this works fast and better than before. 

Finally we made it, did we?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i6avoxcmhxyvzvz0t7hu.png)

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](https://gist.github.com/RaguRam1991/105286b4aa26e07aa4ead64057d10a90)