简体   繁体   English

使用嵌套 JSON 反应本机可搜索平面列表

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM