首页 > 解决方案 > 在 React Native Flatlist 中添加搜索栏没有响应

问题描述

在我的 React Native 应用程序中,我希望能够搜索和显示歌曲,我尝试实现搜索功能,但似乎没有一个工作。下面的代码只允许我输入一个字母,当我输入一个字母时,我的 android 设备键盘消失了,我的列表仍然存在(不会触发搜索)。

请我需要帮助以使搜索功能正常工作,以便在用户搜索歌曲时显示我的搜索歌曲。

这是我的播放器列表代码:

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

这是我要搜索和显示 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;

标签: javascriptreactjsreact-nativereact-native-android

解决方案


所以,这里的事情是所有东西都在同一个组件中,当你运行一个setData或者setQuery你更新整个组件时,你的键盘就会被重置。

关于您的列表未更新,您的代码似乎是一个小错字:

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

但是您还需要更新您的状态声明,这样您就不会从一个空列表开始,如下所示:

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

对此:

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

好的,这应该解决列表中的无过滤器,因为现在您将使用您在过滤器函数上设置的变量,但是当您更新整个组件时,您的键盘关闭问题将继续发生。每个文本更改。我认为这是一个很好的解决方案:

使用某种全局状态管理(例如:Context 或 Redux,您也可以使用 mobx 实现此解决方案)这样您就可以创建一个名为<ListHeader />example 的单独组件并将您的查询更新放在那里并更新全局状态上的列表值,这不会导致您的组件完全重新加载,只是列表会更新并且您可以保持字段焦点,也许这对您来说是一个新概念,所以我在这里分享一个使用 Context 的示例:

工作示例:

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

静态代码:

    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;

祝您的项目成功。


推荐阅读