[英]React Native Searchable Flatlist using Nested JSON
I am trying to make a searchable flatlist for skills using the below JSON file:我正在尝试使用以下 JSON 文件制作可搜索的技能列表:
const employeeList = [
{
id: "1",
name: "John",
image: require("../images/John.png"),
skills: [
{ id: 1, name: "Cooking" },
{ id: 2, name: "Climbing" },
],
},
{
id: "2",
name: "Pat",
image: require("../images/Pat.png"),
skills: [
{ id: 1, name: "Cooking" },
{ id: 2, name: "Rowing" },
],
},
];
export default employeeList;
I was successful in making a screen that will display and allow me to search for employee names but I would like to make a searchable flatlist with all the skills while also displaying the employee name who has that skill.我成功地制作了一个可以显示并允许我搜索员工姓名的屏幕,但我想制作一个包含所有技能的可搜索平面列表,同时还显示具有该技能的员工姓名。 I don't need them to be unique.我不需要它们是独一无二的。 In my code below I have managed to display all employees and their skills however my search feature only filters for the employee name.在我下面的代码中,我设法显示了所有员工及其技能,但是我的搜索功能仅过滤员工姓名。
// Searching using Search Bar Filter in React Native List View
// https://aboutreact.com/react-native-search-bar-filter-on-listview/
// import React in our code
import React, { useState, useEffect } from "react";
// import all the components we are going to use
import {
SafeAreaView,
Text,
StyleSheet,
View,
FlatList,
TextInput,
Image,
TouchableOpacity,
} from "react-native";
// import employee json
import employeeList from "../json/employee";
const AllListScreen = ({ navigation, route }) => {
const [search, setSearch] = useState("");
const [filteredDataSource, setFilteredDataSource] = useState([]);
const [masterDataSource, setMasterDataSource] = useState([]);
// set employee json as filter source
useEffect(() => {
setFilteredDataSource(employeeList);
setMasterDataSource(employeeList);
// skills show as undefined unless index is specified
console.log(JSON.stringify(employeeList[0].skills));
}, []);
const searchFilterFunction = (text) => {
// Check if searched text is not blank
if (text) {
// Inserted text is not blank
// Filter the masterDataSource
// Update FilteredDataSource
const newData = masterDataSource.filter(function (item) {
const itemData = item.name ? item.name.toUpperCase() : "".toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredDataSource(newData);
setSearch(text);
} else {
// Inserted text is blank
// Update FilteredDataSource with masterDataSource
setFilteredDataSource(masterDataSource);
setSearch(text);
}
};
const ItemView = ({ item, index }) => {
return (
// Flat List Item
<View>
// use map to display all skills under employee
{item.skills.map((v, i) => (
<>
<TouchableOpacity
onPress={() => console.log(v.name)}
style={styles.itemStyle}
key={item.id}
>
<Image
source={{ uri: "https://source.unsplash.com/random" }}
style={{ height: 50, width: 50 }}
/>
<View style={styles.textPortion}>
<Text>{item.name}</Text>
<Text>{v.name.toUpperCase()}</Text>
</View>
</TouchableOpacity>
<ItemSeparatorView />
</>
))}
</View>
);
};
const ItemSeparatorView = () => {
return (
// Flat List Item Separator
<View
style={{
height: 0.5,
width: "100%",
backgroundColor: "#C8C8C8",
}}
/>
);
};
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.container}>
<TextInput
style={styles.textInputStyle}
onChangeText={(text) => searchFilterFunction(text)}
value={search}
underlineColorAndroid="transparent"
placeholder="Search Here"
/>
<FlatList
data={filteredDataSource}
keyExtractor={(item, index) => index.toString()}
renderItem={ItemView}
/>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: "#FFFFFF",
},
itemStyle: {
flex: 1,
padding: 8,
flexDirection: "row",
},
textInputStyle: {
height: 50,
borderWidth: 1,
paddingLeft: 20,
margin: 6,
borderColor: "#009688",
backgroundColor: "#FFFFFF",
borderRadius: 5,
},
textPortion: {
flexWrap: "wrap",
flexShrink: 1,
marginLeft: 6,
},
});
export default AllListScreen;
Here is an image of how it is displayed but as stated the search only works on the employee name while I want it to work on the skill:这是它如何显示的图像,但如前所述,搜索仅适用于员工姓名,而我希望它适用于技能:
Any help is much appreciated.任何帮助深表感谢。 Thanks.谢谢。
I managed to get this working by restructuring the JSON in an array:我设法通过在数组中重组 JSON 来实现这一点:
skillArray = [];
for (var key in employeeList) {
if (employeeList.hasOwnProperty(key)) {
for (item in employeeList[key].skills) {
skillArray.push({
name: employeeList[key].name,
skill: employeeList[key].skills[item].name,
});
}
}
}
Then I changed my search filter to target the skill instead of the name:然后我更改了搜索过滤器以针对技能而不是名称:
// set employee json as filter source
useEffect(() => {
setFilteredDataSource(skillArray);
setMasterDataSource(skillArray);
// skills show as undefined unless index is specified
console.log(JSON.stringify(employeeList[0].skills));
}, []);
const searchFilterFunction = (text) => {
// Check if searched text is not blank
if (text) {
// Inserted text is not blank
// Filter the masterDataSource
// Update FilteredDataSource
const newData = masterDataSource.filter(function (item) {
const itemData = item.skill ? item.skill.toUpperCase() : "".toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredDataSource(newData);
setSearch(text);
} else {
// Inserted text is blank
// Update FilteredDataSource with masterDataSource
setFilteredDataSource(masterDataSource);
setSearch(text);
}
};
And my updated ItemView:还有我更新的 ItemView:
const ItemView = ({ item }) => {
return (
// Flat List Item
<View style={styles.itemStyle}>
<Image
source={{ uri: "https://source.unsplash.com/random" }}
style={{ height: 50, width: 50 }}
/>
<Text style={styles.textPortion}>
{item.name.toUpperCase()}
{"\n"}
{item.skill.toUpperCase()}
</Text>
</View>
);
};
I'm not sure if this is the optimal approach but hopefully it helps someone.我不确定这是否是最佳方法,但希望它对某人有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.