Benjamin Ikwuagwu
Benjamin Ikwuagwu

Reputation: 459

Adding Search Bar In React Native Flatlist Is not Responding

In my React Native application I want to be able to search and display songs, I have tried implementing search function, but none seems to work. The code below only allows me to type one letter, and when I type one letter my android device keyboard disappears my list will still remain (no search will be triggered).

Please I need help to make the search feature work in order for my search songs to display when User searches for songs.

Here's my player list code:

import React, { useEffect, useState } from 'react';
import { 
    SafeAreaView, 
    View, 
    FlatList,  
    ScrollView, 
    TouchableOpacity,
    ActivityIndicator,
    TextInput,
    } from 'react-native';
import Sound from 'react-native-sound';
import { Avatar, Text } from '@ui-kitten/components';
import Ionicons from 'react-native-vector-icons/Ionicons';
import filter from 'lodash.filter';

import songs from '../../SongData';

import styles from './styles';



const SonglistScreen = () => {
    const [isDisabled, setisDisabled] = useState(false);
    const [loading, setLoading] = useState(false);
    const [isPlayed, setIsPlayed] = useState(false);
    const [data, setData] = useState([]);
    const [query, setQuery] = useState('');
    const [song, setSong] = useState([]);
    const [fullData, setFullData] = useState([]);


    useEffect(() => {
      getData();
    }, []);

    const getData = () => {
      const res = (songs);
      setData(res);
      setFullData(res);
    };

.....//
......//

const renderItem = ({ item, index }) => (
    <ScrollView style={{flex: 1}}>
        <View style={styles.item}>
          <Avatar
                source={{ uri: item.picture }}
                style={{ marginRight: 16 }} 
                size='giant'
          />
          <Text style={styles.title} category='s1'> {item.title} </Text>
        </View>
        <Text 
          style={{ 
            color: '#444',
            fontSize: 11, 
            marginLeft: 112, 
            marginVertical: -20, 
            bottom: 27 
          }}
          category='s1'
          >{item.ArtistName} 
        </Text>
        <Text 
          style={{ 
            color: '#999', 
            marginLeft: 110, 
            marginVertical: -20,
            top: 10
          }}
          category='s1'
          >Genre: {item.genre} 
        </Text>
        <View style={{flexDirection: 'row', left: '230%', bottom: '7%'}}>
              <TouchableOpacity 
                onPress={()=>playSound(item, index)} 
                style={{padding: 10, top: 30, left: 30}}
              >
                <Ionicons name="play" color={isPlayed ? 'red' : '#555555'} size={22} />
              </TouchableOpacity>
              <TouchableOpacity 
                onPress={()=>stopSound(index)} 
                style={{padding: 10, top: 30, left: 20}}
              >
                <Ionicons name="stop" color="#555555" size={22} />
              </TouchableOpacity>
            </View>
    </ScrollView>
  );

  const handleSearch = text => {
    let newData = songs.filter(item =>{
      const itemData = `${item.title.toUpperCase()}`;
      const textData = text.toUpperCase();

      if (text.length > 0) {
        return itemData.indexOf(textData) > -1;
      }
    });
    setData(newData);
    setQuery(text);
  };


  const renderHeader = () => {
    return (
      <View
        style={{
          backgroundColor: '#fff',
          padding: 10,
          marginVertical: 10,
          borderRadius: 20
        }}
      >
        <TextInput
          autoCapitalize="none"
          autoCorrect={false}
          clearButtonMode="always"
          value={query}
          onChangeText={text => handleSearch(text)}
          placeholder="Search songs"
          style={{ backgroundColor: '#fff', paddingHorizontal: 20 }} 
        />
      </View>
    )
  };



  const renderFooter = () => {
    if (!loading) return null

    return (
        <View
            style={{
                paddingVertical: 15,
                borderTopWidth: 1,
                borderColor: '#CED0CE',
            }}
        >
            <ActivityIndicator animating size='large' />
        </View>
    );
  }

...../
...../

return (
    <SafeAreaView style={styles.container}>
      <FlatList
        data={songs}
        renderItem={renderItem}
        keyExtractor={item => item.id}
        ItemSeparatorComponent={renderSeparator}
        ListHeaderComponent={renderHeader}
        ListFooterComponent={renderFooter}
      />
    </SafeAreaView>
  );
}

This is the data I want to search and display songdata.js:

const songs = [
    {
        id: 1,
        title: 'Hero',
        ArtistName: 'Bethany Dilon',
        genre: 'pop',
        isRequire: true,
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.18169-9/16195530_10211997136709517_8578854309931959016_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=09cbfe&_nc_eui2=AeEvt5zlNj1bM87SMIgRXz8VjFbfh8f8mfyMVt-Hx_yZ_ISR6pzt6j1tOqssNCwDfnM&_nc_ohc=oQeQeYLPRz8AX_n81Yh&_nc_ht=scontent-los2-1.xx&oh=d87b3097c543a39067095bacfbeb004d&oe=609BF1DC',
        url: require('../../assets/songs/Hero.mp3'),
    },

    {
        id: 2,
        title: 'Advertising URL',
        ArtistName: 'Bethany Dilon',
        genre: 'Soft Rock',
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url:
            'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/advertising.mp3',
    },

    {
        id: 3,
        title: 'Stronger',
        ArtistName: 'Bethany Dilon',
        genre: 'Country',
        isRequire: true,
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: require('../../assets/songs/Stronger.mp3'),
    },

    {
        id: 4,
        title: 'Faded',
        ArtistName: 'Luchee',
        genre: 'Techno',
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Faded.mp3',
    },

    {
        id: 5,
        title: 'Solo',
        ArtistName: 'Solo Cosmos',
        genre: 'Afrobeat',
        isRequire: true,
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Solo.mp3',
    },

    {
        id: 6,
        title: 'Death Bed',
        ArtistName: 'Omowunmi feat Wizkid',
        genre: 'Afrocentric',
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: 'https://github.com/ShivamJoker/sample-songs/raw/master/death%20bed.mp3',
    },

    {
        id: 7,
        title: 'Hero',
        ArtistName: 'Bethany Dilon',
        genre: 'pop',
        isRequire: true,
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.18169-9/16195530_10211997136709517_8578854309931959016_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=09cbfe&_nc_eui2=AeEvt5zlNj1bM87SMIgRXz8VjFbfh8f8mfyMVt-Hx_yZ_ISR6pzt6j1tOqssNCwDfnM&_nc_ohc=oQeQeYLPRz8AX_n81Yh&_nc_ht=scontent-los2-1.xx&oh=d87b3097c543a39067095bacfbeb004d&oe=609BF1DC',
        url: require('../../assets/songs/Hero.mp3'),
    },

    {
        id: 8,
        title: 'Advertising URL',
        ArtistName: 'Bethany Dilon',
        genre: 'Soft Rock',
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url:
            'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/advertising.mp3',
    },

    {
        id: 9,
        title: 'Stronger',
        ArtistName: 'Bethany Dilon',
        genre: 'Country',
        isRequire: true,
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: require('../../assets/songs/Stronger.mp3'),
    },

    {
        id: 10,
        title: 'Faded',
        ArtistName: 'Luchee',
        genre: 'Techno',
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Faded.mp3',
    },

    {
        id: 11,
        title: 'Solo',
        ArtistName: 'Solo Cosmos',
        genre: 'Afrobeat',
        isRequire: true,
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Solo.mp3',
    },

    {
        id: 12,
        title: 'Death Bed',
        ArtistName: 'Omowunmi feat Wizkid',
        genre: 'Afrocentric',
        picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
        url: 'https://github.com/ShivamJoker/sample-songs/raw/master/death%20bed.mp3',
    },
    
  ];

  export default songs;

Upvotes: 0

Views: 1159

Answers (1)

Lu&#237;s C Meireles
Lu&#237;s C Meireles

Reputation: 469

So, the thing here is that everything is inside the same component and when you run a setData or setQuery you update the whole component, and your keyboard is reseted.

About your list not been updated, it seems to be a small typo on your code:

return (
  <SafeAreaView style={styles.container}>
    <FlatList
      // data={songs} <-- here you should be using data
      data={data} // something like this
      renderItem={renderItem}
      keyExtractor={item => item.id}
      ItemSeparatorComponent={renderSeparator}
      ListHeaderComponent={renderHeader}
      ListFooterComponent={renderFooter}
    />
  </SafeAreaView>
);

But you would also need to update your state declarations as well so you don't start with an empty list, from this:

const [data, setData] = useState([]);

to this:

const [data, setData] = useState(songs);

Ok, this should solve the no filter on the list as now you will be using the variable you set on your filter function, but the problem about your keyboard dismissing will keep happening as you update your whole component each text change. Here's a good solution in my opinion:

Use some sort of global state management (Eg.: Context or Redux, you could also achieve this solution with mobx) this way you can create a separated component called <ListHeader /> for example and put your query update there and update the list value on the global state, this will not cause a full reload on your component, just the list will update and you can keep the field focus, maybe it's a new concept for you so I'm sharing an example using Context here:

Working Example:

https://codesandbox.io/s/contextexample-p28z5?file=/src/App.js

Static Code:

    import React, { useContext, useState } from "react";
import { Text, View, FlatList, TextInput } from "react-native";

const data = [
  { name: "qweqwe" },
  { name: "aaaaaa" },
  { name: "eeeeeeeee" },
  { name: "4" }
];

// List Context and ListProvider can be togheter in the same file
const ListContext = React.createContext({
  list: [],
  setList: () => {}
});
const ListProvider = ({ children }) => {
  const [list, setList] = useState(data);

  return (
    <ListContext.Provider value={{ list, setList }}>
      {children}
    </ListContext.Provider>
  );
};

const Item = ({ item }) => {
  return (
    <View>
      <Text>{item.name}</Text>
    </View>
  );
};

const Header = () => {
  const [text, setText] = useState("");
  const listContext = useContext(ListContext);

  const updateQuery = (str) => {
    listContext.setList(data.filter((d) => d.name.indexOf(str) > -1));
    setText(str);
  };

  return (
    <View>
      <TextInput value={text} onChangeText={updateQuery} />
    </View>
  );
};

const ListScreen = () => {
  return (
    <ListContext.Consumer>
      {(context) => (
        <View style={{ flex: 1 }}>
          <FlatList
            data={context.list}
            keyExtractor={(i) => i.name}
            renderItem={({ item }) => <Item item={item} />}
            ListHeaderComponent={Header}
          />
        </View>
      )}
    </ListContext.Consumer>
  );
};

const App = () => {
  return (
    <ListProvider>
      <ListScreen />
    </ListProvider>
  );
};

export default App;

Wish success on your project.

Upvotes: 1

Related Questions