DEV Community

Cover image for Search Filter or Search In List React Native
RamR
RamR

Posted on • Updated on

Search Filter or Search In List React Native

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

Enter fullscreen mode Exit fullscreen mode

Image description

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',
  },
];

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

Image description

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Image description

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

Enter fullscreen mode Exit fullscreen mode

Image description

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


Enter fullscreen mode Exit fullscreen mode

Image description

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

Enter fullscreen mode Exit fullscreen mode

Image description

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

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

Top comments (0)