React Native Hooks Search Filter Flat List

帅比萌擦擦* 提交于 2020-05-30 08:47:06

问题


I am trying to make a Covid19 React Native Expo app. It contains a search filter from which user will select a country then the selected country results will be shown to the user. I keep getting this error on my Android device "Unexpected Identifier You" while on web pack the countries load but they dont filter correctly.
Working Snack Link: https://snack.expo.io/@moeez71/ac5758 Here is my code

import React, { useState, useEffect } from "react";
import {
  ActivityIndicator,
  Alert,
  FlatList,
  Text,
  StyleSheet,
  View,
  TextInput,
} from "react-native";

export default function ABCDEE() {
  const [arrayholder, setArrayholder] = useState([]);
  const [text, setText] = useState("");
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  const fetchAPI = () => {
    return fetch("https://api.covid19api.com/countries")
      .then((response) => response.json())
      .then((responseJson) => {
        setData(responseJson);
        setLoading(false);
        setArrayholder(responseJson);
      })
      .catch((error) => {
        console.error(error);
      });
  };

  useEffect(() => {
    fetchAPI();
  });

  const searchData = (text) => {
    const newData = arrayholder.filter((item) => {
      const itemData = item.Country.toUpperCase();
      const textData = text.toUpperCase();
      return itemData.indexOf(textData) > -1;
    });

    setData(newData);
    setText(text);
  };

  const itemSeparator = () => {
    return (
      <View
        style={{
          height: 0.5,
          width: "100%",
          backgroundColor: "#000",
        }}
      />
    );
  };

  return (
    <View>
      {loading === false ? (
        <View style={styles.MainContainer}>
          <TextInput
            style={styles.textInput}
            onChangeText={(text) => searchData(text)}
            value={text}
            underlineColorAndroid="transparent"
            placeholder="Search Here"
          />

          <FlatList
            data={data}
            keyExtractor={(item, index) => index.toString()}
            ItemSeparatorComponent={itemSeparator}
            renderItem={({ item }) => (
              <Text style={styles.row}>{item.Country}</Text>
            )}
            style={{ marginTop: 10 }}
          />
        </View>
      ) : (
        <Text>loading</Text>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  MainContainer: {
    paddingTop: 50,
    justifyContent: "center",
    flex: 1,
    margin: 5,
  },

  row: {
    fontSize: 18,
    padding: 12,
  },

  textInput: {
    textAlign: "center",
    height: 42,
    borderWidth: 1,
    borderColor: "#009688",
    borderRadius: 8,
    backgroundColor: "#FFFF",
  },
});

回答1:


There are multiple issues with your implementation. I will point out some mistake/ignorance. You can clean up you code accordingly.

  1. Do not create 2 state to keep same data. ie. arrayholder and data.
  2. Change text value on search, don't the data. based on that text filter
  3. Hooks always define some variable to be watched.

Update: Seems there is an issue with flex in android view, i use fixed height it is visible.

Just a hack for android issue. minHeight

MainContainer: {
    paddingTop: 50,
    justifyContent: 'center',
    flex: 1,
    margin: 5,
    minHeight: 800,
  },

Working link: https://snack.expo.io/kTuT3uql_

Updated code:

 import React, { useState, useEffect } from 'react';
import {
  ActivityIndicator,
  Alert,
  FlatList,
  Text,
  StyleSheet,
  View,
  TextInput,
} from 'react-native';

export default function ABCDEE() {
  const [text, setText] = useState('');
  const [state, setState] = useState({ data: [], loading: false }); // only one data source
  const { data, loading } = state;
  const fetchAPI = () => {
    //setState({data:[], loading: true});
    return fetch('https://api.covid19api.com/countries')
      .then(response => response.json())
      .then(data => {
        console.log(data);
        setState({ data, loading: false }); // set only data
      })
      .catch(error => {
        console.error(error);
      });
  };
  useEffect(() => {
    fetchAPI();
  }, []); // use `[]` to avoid multiple side effect

  const filterdData = text // based on text, filter data and use filtered data
    ? data.filter(item => {
        const itemData = item.Country.toUpperCase();
        const textData = text.toUpperCase();
        return itemData.indexOf(textData) > -1;
      })
    : data; // on on text, u can return all data
  console.log(data);
  const itemSeparator = () => {
    return (
      <View
        style={{
          height: 0.5,
          width: '100%',
          backgroundColor: '#000',
        }}
      />
    );
  };

  return (
    <View>
      {loading === false ? (
        <View style={styles.MainContainer}>
          <TextInput
            style={styles.textInput}
            onChangeText={text => setText(text)}
            value={text}
            underlineColorAndroid="transparent"
            placeholder="Search Here"
          />
          <FlatList
            data={filterdData}
            keyExtractor={(item, index) => index.toString()}
            ItemSeparatorComponent={itemSeparator}
            renderItem={({ item }) => (
              <Text style={styles.row}>{item.Country}</Text>
            )}
            style={{ marginTop: 10 }}
          />
        </View>
      ) : (
        <Text>loading</Text>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  MainContainer: {
    paddingTop: 50,
    justifyContent: 'center',
    //flex: 1,
    margin: 5,
    height: 800,
  },

  row: {
    fontSize: 18,
    padding: 12,
  },

  textInput: {
    textAlign: 'center',
    height: 42,
    borderWidth: 1,
    borderColor: '#009688',
    borderRadius: 8,
    backgroundColor: '#333',
  },
});



回答2:


You had made two mistakes in the above code

  1. useEffect second parameter should be a empty array for it act as componentDidMount()

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

  2. in FlatList renderItem need to destructure the item.

      renderItem={( {item}  ) => <Text style={styles.row}
       >{item.Country}</Text>}
    

Working code

    import React, {useState, useEffect} from "react"
import { ActivityIndicator, Alert, FlatList, Text, StyleSheet, View, TextInput } from 'react-native';

export default function ABCDEE(){


  const [arrayholder,setArrayholder] =useState([])
  const[text, setText] = useState('')
  const[data, setData] = useState([])
  const [loading , setLoading] = useState(true)

  const fetchAPI = ()=> {
    return fetch('https://api.covid19api.com/countries')
    .then((response) => response.json())
    .then((responseJson) => {
        setData(responseJson)
        setLoading(false)
        setArrayholder(responseJson)
    }

    )
    .catch((error) => {
        console.error(error);
      });
}

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


  const searchData= (text)=>  {
    const newData = arrayholder.filter(item => {
      const itemData = item.Country.toUpperCase();
      const textData = text.toUpperCase();
      return itemData.indexOf(textData) > -1
    });

      setData(newData)
      setText(text)
    }

   const itemSeparator = () => {
      return (
        <View
          style={{
            height: .5,
            width: "100%",
            backgroundColor: "#000",
          }}
        />
      );
    }

      return (
          <View style={{flex:1}} >
    {loading === false ?  
        <View style={styles.MainContainer}>

        <TextInput 
         style={styles.textInput}
         onChangeText={(text) => searchData(text)}
         value={text}
         underlineColorAndroid='transparent'
         placeholder="Search Here" />

        <FlatList
          data={data}
          keyExtractor={ (item, index) => index.toString() }
          ItemSeparatorComponent={itemSeparator}
          renderItem={( {item}  ) => <Text style={styles.row}
           >{item.Country}</Text>}
          style={{ marginTop: 10 }} />

      </View>
      : <Text>loading</Text>}

      </View>
    );
  }


const styles = StyleSheet.create({

  MainContainer: {
    paddingTop: 50,
    justifyContent: 'center',
    flex: 1,
    margin: 5,

  },

  row: {
    fontSize: 18,
    padding: 12
  },

  textInput: {

    textAlign: 'center',
    height: 42,
    borderWidth: 1,
    borderColor: '#009688',
    borderRadius: 8,
    backgroundColor: "#FFFF"

  }
});



回答3:


It seems like the error comes from the catch block when you fetch your data. The response comes with a 200 status, so it's not an issue with the endpoint itself. I console.logged the response and it seems fine. The problem is when you parse the response and try to use it in the second then() block, so the catch block fires up. I could not debug it right in the editor you use, but I would check what type of object I'm receiving from the API call.




回答4:


This is not a direct answer to your question but I didn't want this to get lost in the comments as it is directly related with your efforts on this app.

App Store and Google Play Store no longer accept apps that have references to Covid-19 https://developer.apple.com/news/?id=03142020a

You can only publish apps about Covid-19 if you are reputable source like a government's health department.

Therefore, I urge you to reevaluate your efforts on this app.



来源:https://stackoverflow.com/questions/61966355/react-native-hooks-search-filter-flat-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!