I am new to using APIs with React Native, I have a few things figured out but what I'm trying to do now is create a Search function. I've tried a few things so far, but either the function isn't being called, or I get an error about the function being called as an object. Also, I am using axios to make this API call
Here's what I've got so far.
export default class CategoryScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
isVisible: true,
city: '280',
isLoading: true,
search: ''
}
}
async componentDidMount() {
try {
const id = this.props.navigation.state.params.category;
const city = this.state.city;
const result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?city_id=${city}&category=${id}`,
headers: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
}
});
this.setState({ data: result.data.restaurants });
} catch (err) {
console.log(err);
} finally {
this.setState({ isLoading: false });
}
}
updateSearch = search => {
this.setState({ search });
};
searchReq = () => {
axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?city_id=${city}&q${search}&category=${id}`,
header: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
}
});
this.setState({ data: result.data.restaurants });
}
render() {
const { search } = this.state;
return (
<SearchBar
placeholder="Type Here..."
onChangeText={this.updateSearch}
onSubmitEditing={this.searchReq}
value={search}
/>
)
}
}
If there is a more advanced way of doing it I'm open to learning something new, I just want to accomplish what I want to do. Also, I know that if my current method worked it'd still cause problems if the user adds a space in between, so I'm very open to learning new and more advanced ways of doing this
Here is the expo snack https://snack.expo.io/SJoIr8u1I
I noted couple of mistake of your search function.
city
, search
& id
value which are not in searchReq()
result.data.restaurants
value before you assign it to data: result.data.restaurants
Since you already assign this.setState({ search })
I get that value inside searchReq()
as below,
searchReq = async () => {
try {
const result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?city_id=280&q${this.state.search}&category=11`,
headers: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
}
});
this.setState({ data: result.data.restaurants });
} catch (error) {
this.setState({ data: [] });
console.log(error);
}
}
So full source code will be like this
import React, { Component } from 'react';
import {
View,
Text,
FlatList,
StyleSheet,
TouchableOpacity,
Dimensions,
ActivityIndicator,
} from 'react-native';
import { Card, Image, SearchBar, Icon } from 'react-native-elements';
import Logo from '../assets/Logo.png'
import axios from 'axios';
const SCREEN_WIDTH = Dimensions.get('window').width;
const SCREEN_HEIGHT = Dimensions.get('window').height;
export default class CategoryScreen extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isVisible: true,
city: '280',
isLoading: true,
search: ''
}
}
async componentDidMount() {
try {
const result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?city_id=280&category=11`,
headers: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
}
});
this.setState({
data: result.data.restaurants,
isLoading: false
});
} catch (err) {
this.setState({ isLoading: false });
console.log(err);
}
}
updateSearch = search => {
this.setState({ search });
};
searchReq = async () => {
try {
const result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?city_id=280&q${this.state.search}&category=11`,
headers: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
}
});
this.setState({ data: result.data.restaurants });
} catch (error) {
this.setState({ data: [] });
console.log(error);
}
}
render() {
const { search } = this.state;
return (
<View>
<View style={styles.header}>
<Image source={Logo} style={{ resizeMode: 'stretch', width: 50, height: 50, alignSelf: 'center', justifyContent: 'center', marginTop: 30 }} />
<Icon
raised
name='location'
type='octicon'
color='#f50'
onPress={() => this.setState({ isModalVisible: !this.state.isModalVisible })}
containerStyle={{ alignSelf: 'flex-end', marginRight: 20, marginTop: -60 }} />
</View>
<SearchBar
placeholder="Type Here..."
onChangeText={this.updateSearch}
onSubmitEditing={this.searchReq}
value={search}
inputStyle={{ backgroundColor: 'steelblue', color: 'white' }}
inputContainerStyle={{ backgroundColor: 'steelblue', fontColor: 'white' }}
containerStyle={{ backgroundColor: 'steelblue', borderBottomColor: 'transparent', borderTopColor: 'transparent' }}
placeholderTextColor='white'
/>
{
this.state.isLoading ?
<View style={{ flex: 1, marginTop: 200 }}>
<ActivityIndicator style={{ color: 'red' }} />
</View> :
(
this.state.data.length == 0 ?
<View style={{ flex: 1, padding: 20, marginTop: 100 }}>
<Text style={{ color: '#000', fontWeight: 'bold' }}>No restaurants from selected category</Text>
</View> :
<View style={{ flexDirection: 'column' }}>
<FlatList
keyExtractor={item => item.id}
data={this.state.data}
renderItem={({ item }) =>
<TouchableOpacity onPress={() => console.log(item.restaurant.location.city)}>
<Card style={{ width: SCREEN_WIDTH }}>
<Image style={{ width: SCREEN_WIDTH / 3, height: 130 }} resizeMode="stretch" source={{ uri: item.restaurant.thumb }} />
<Text style={{ color: '#000', fontWeight: 'bold' }}>{item.restaurant.name} </Text>
</Card>
</TouchableOpacity>
}
/>
</View>
)
}
</View>
)
}
}
const styles = StyleSheet.create({
header: {
backgroundColor: '#ff4714',
height: SCREEN_HEIGHT / 8,
},
});
Hope this helps you.