问题
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.
- Do not create 2 state to keep same data. ie. arrayholder and data.
- Change text value on search, don't the data. based on that text filter
- 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
useEffect second parameter should be a empty array for it act as componentDidMount()
useEffect(() => { fetchAPI(); },[])
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