A simple get request in react. What am i doing wrong - react-native

IM doing a simple get Request. I want to put the response in my state array.
export default function App() {
state = { features: [] };
useEffect(() => {
fetch(featuresURL, oParam)
.then((response) => response.json())
.then((data) => {
this.setState({ features: data });
})
.catch(() => alert("Bad request"));
}, []);
what am i doing wrong ?
Im completely new to react. Im just learning
In fact what im trying to achieve is get markers on my react native maps.
this is my code:
export default function App() {
const [data, setData] = useState([]);
useEffect(() => {
fetch(featuresURL, oParam)
.then((response) => response.json())
.then((json) => setData(json))
.catch(() => alert("Bad request"));
}, []);
mapMarkers = () => {
return this.data.features.map((feature) => (
<Geojson
geojson={feature}
strokeColor="red"
fillColor="green"
strokeWidth={2}
/>
));
};
return (
<MapView
style={{ flex: 1 }}
mapType="mutedStandard"
initialRegion={{
latitude: 37.1,
longitude: -95.7,
latitudeDelta: 10,
longitudeDelta: 45,
}}
>
{this.mapMarkers()}
</MapView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
width: "100%",
height: "100%",
},
});

Related

React Native - Get Location latitude and longitude using react-native-get-location

I am creating an app which uses the phone's location. I would like to be able to get the latitude and longitude and using it as part of an api address.
I have been following this sample code using react-native-get-location and have been able to print the information in json formate but can't pull the latitude and longitude and use them.
react-native-get-location
Here is my code.
import GetLocation from 'react-native-get-location'
export default class App extends React.Component {
constructor (props) {
super(props);
this.state = {
isLoading: true,
latitude: null,
longitude: null,
location: null
};
}
_requestLocation = () => {
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 150000,
})
.then(location => {
this.setState ({
location,
isLoading: false,
});
})
.catch(error => {
const { code, message} = error;
if (code === 'CANCELLED') {
Alert.alert('location cancelled by user or by another request');
}
if (code === 'UNAVAILABLE') {
Alert.alert('Location service is disabled or unavailable');
}
if (code === 'TIMEOUT') {
Alert.alert('Location request timed out');
}
if (code === 'UNAUTHORIZED') {
Alert.alert('Authorization denied')
}
this.setState({
location: null,
isLoading: false,
});
});
}
componentDidMount() {
GetLocation.getCurrentPosition(async (info) => {
const location = await GetLocation(
info.coords.latitude,
info.coords.longitude
);
})
const fetch = require('node-fetch');
fetch('https://api.weatherapi.com/v1/forecast.json?&q=London', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
}).then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson,
})
}).catch((error) => {
console.error(error);
});
}
render() {
const {location, isLoading} = this.state;
if (this.state.isLoading) {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ActivityIndicator />
</View>
);
}
return (
<View style={{flex:1, paddingTop: 20}}>
<Text>{JSON.stringify(location, 0, 2)}</Text>
<View style={{flex:1, flexDirection: 'row', textAlign: 'center', paddingLeft: 90}}>
<Button
disabled={isLoading}
title="Get Location"
onPress={this._requestLocation}
/>
</View>
</View>
)
}
}
Use expo-location instead of react-native-get-location as it is very easy to implement.
Here is the working app: Expo Snack
Screenshot:
import React, { useEffect, useState } from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
let apiKey = 'YOUR_API_KEY';
import * as Location from 'expo-location';
export default function App() {
const [location, setLocation] = useState(null);
const [errorMsg, setErrorMsg] = useState(null);
const [address, setAddress] = useState(null);
// const [getLocation, setGetLocation] = useState(false);
const getLocation = () => {
(async () => {
let { status } = await Location.requestPermissionsAsync();
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied');
}
Location.setGoogleApiKey(apiKey);
console.log(status);
let { coords } = await Location.getCurrentPositionAsync();
setLocation(coords);
console.log(coords);
if (coords) {
let { longitude, latitude } = coords;
let regionName = await Location.reverseGeocodeAsync({
longitude,
latitude,
});
setAddress(regionName[0]);
console.log(regionName, 'nothing');
}
// console.log();
})();
};
return (
<View style={styles.container}>
<Text style={styles.big}>
{!location
? 'Waiting'
: `Lat: ${location.latitude} \nLong: ${
location.longitude
} \n${JSON.stringify(address?.['subregion'])}`}
</Text>
<TouchableOpacity onPress={getLocation}>
<View
style={{
height: 100,
backgroundColor: 'teal',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
marginTop: 20,
}}>
<Text style={styles.btnText}> GET LOCATION </Text>
</View>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
},
big: {
fontSize: 18,
color: 'black',
fontWeight: 'bold',
},
btnText: {
fontWeight: 'bold',
fontSize: 25,
color: 'white',
},
});
react-native-geolocation-service is a good alternative too for fetching latitude & longitude values.
Example usage:
import GeoLocation from 'react-native-geolocation-service';
const getDeviceCurrentLocation = async () => {
return new Promise((resolve, reject) =>
GeoLocation.getCurrentPosition(
(position) => {
resolve(position);
},
(error) => {
reject(error);
},
{
enableHighAccuracy: true, // Whether to use high accuracy mode or not
timeout: 15000, // Request timeout
maximumAge: 10000 // How long previous location will be cached
}
)
);
};

React-Native Searchable FlatList with Local Json File

I am trying to create a searchable flatlist on this new app I was working on over quarantine. I followed an article on the internet on how to create it and my code so far looks like this:
import React, { Component } from 'react';
import { View, Text, FlatList, ActivityIndicator } from 'react-native';
import { ListItem, SearchBar } from 'react-native-elements';
class FlatListDemo extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
error: null,
};
this.arrayholder = [];
}
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const url = `https://randomuser.me/api/?&results=20`;
this.setState({ loading: true });
fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
data: res.results,
error: res.error || null,
loading: false,
});
this.arrayholder = res.results;
})
.catch(error => {
this.setState({ error, loading: false });
});
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '14%',
}}
/>
);
};
searchFilterFunction = text => {
this.setState({
value: text,
});
const newData = this.arrayholder.filter(item => {
const itemData = `${item.name.title.toUpperCase()} ${item.name.first.toUpperCase()} ${item.name.last.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
data: newData,
});
};
renderHeader = () => {
return (
<SearchBar
placeholder="Type Here..."
lightTheme
round
onChangeText={text => this.searchFilterFunction(text)}
autoCorrect={false}
value={this.state.value}
/>
);
};
render() {
if (this.state.loading) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
);
}
return (
<View style={{ flex: 1 }}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<ListItem
leftAvatar={{ source: { uri: item.picture.thumbnail } }}
title={`${item.name.first} ${item.name.last}`}
subtitle={item.email}
/>
)}
keyExtractor={item => item.email}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
);
}
}
export default FlatListDemo;
This works and all, but how could I alter the makeRemoteRequest function so that I got data from a local json file instead of a url? For example:
makeRemoteRequest = () => {
const url = `../data/userData.json`;
this.setState({ loading: true });
fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
data: res.results,
error: res.error || null,
loading: false,
});
this.arrayholder = res.results;
})
.catch(error => {
this.setState({ error, loading: false });
});
};
I tried this with no success as none of the json data rendered and appeared in the flatlist
The Fetch API is a promise-based JavaScript API for making asynchronous HTTP requests in the browser similar to XMLHttpRequest. If you want to load data from a local JSON file.
First import that file
import Data from '../data/userData.json'
Then assign imported value to your state inside your makeRemoteRequest function
makeRemoteRequest = () => {
this.setState({
data: Data,
});
}
Hope this helps you. Feel free for doubts.

I'm trying to run a search with user input, but my searchInput variable is showing up as undefined?

I'm trying to run a search with user input, but my searchInput variable is showing up as undefined when I run the code. I can't figure out what I'm doing wrong. Thanks for your help!
Here's my code:
import React, { useState } from "react";
import {
TouchableOpacity,
StyleSheet,
View,
Modal,
TextInput
} from "react-native";
import Icon from "react-native-vector-icons/Feather";
import API_KEYS from "../utils/APIKeys";
const SearchScreen = ({ modalVisible, setModalVisible }) => {
const [searchInput, setSearchInput] = useState("");
const [searchResults, setSearchResults] = useState([]);
const searchPlaces = ({ searchInput }) => {
console.log(searchInput);
fetch(
`https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${searchInput}&types=cities&key=${API_KEYS.GOOGLE_MAPS_API_KEY}`
)
.then(res => res.json())
.then(json => {
console.log(json);
});
};
return (
<Modal animationType="fade" transparent={false} visible={modalVisible}>
<TouchableOpacity
style={styles.iconContainer}
onPress={() => setModalVisible(false)}
>
<Icon name="x" size={30} />
</TouchableOpacity>
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Search places…"
placeholderTextColor="#666"
value={searchInput}
onChangeText={newValue => setSearchInput(newValue)}
onEndEditing={searchInput => searchPlaces(searchInput)}
/>
</View>
</Modal>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
height: "100%",
justifyContent: "center",
marginHorizontal: 20
},
input: {
fontFamily: "hermitRegular",
fontSize: 24
},
iconContainer: {
zIndex: 10,
position: "absolute",
top: 60,
right: 25
}
});
export default SearchScreen;
Here's the response. The first line is the content of searchInput and the second is the response from the Google API.
undefined
Object {
"predictions": Array [],
"status": "INVALID_REQUEST",
}
I figured out what was wrong.
This needed updating:
const searchPlaces = ({ searchInput }) => {
console.log(searchInput);
fetch(
`https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${searchInput}&types=cities&key=${API_KEYS.GOOGLE_MAPS_API_KEY}`
)
.then(res => res.json())
.then(json => {
console.log(json);
});
};
To this:
const searchPlaces = () => {
console.log(searchInput);
fetch(
`https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${searchInput}&types=(cities)&key=${API_KEYS.GOOGLE_MAPS_API_KEY}`
)
.then(res => res.json())
.then(json => {
console.log(json);
});
};

How can I render my markers inside the ClusteredMapView?

I am trying to render the markers inside the component <ClusteredMapView/> but it do not happen, just render the marker with none markers...
Bellow some code:
render() {
return (
<ClusteredMapView
style={{ flex: 1 }}
data={this.state.data}
initialRegion={INIT_REGION}
ref={r => {
this.map = r;
}}
renderMarkerS={this.renderMarkerS}
renderCluster={this.renderCluster}
/>
);
}
}
here is the renderMarkers function:
renderMarkerS = item =>
this.state.markers.map((marker, index) => {
console.log('Location picker Marker', coords);
const coords = {
location: {
latitude: JSON.parse(item.latitude),
longitude: JSON.parse(item.longitude),
},
};
return (
<Marker
onPress={this.pickLocationHandler}
ref={mark => (marker.mark = mark)}
key={index || Math.random()}
title={'Parada'}
description={marker.hora}
tracksViewChanges={!this.state.initialized}
{...this.props}
pinColor={'tomato'}
coordinate={JSON.parse(item.location)}
//coordinate={coords}
>
{this.props.children}
</Marker>
);
});
With:
componentDidMount() {
return fetch(
'https://gist.githubusercontent.com/MatheusCbrl/bba7db1c0dbc68be2f26d5c7e15649b6/raw/0fab4ea3b493dcd15e95f172cd0a251724efbc45/ParadasDiurno.json'
)
.then(response => response.json())
.then(responseJson => {
// just setState here e.g.
this.setState({
data: responseJson,
isLoading: false,
});
})
.catch(error => {
console.error(error);
});
}
My data is:
[
{
"id": "1",
"location": {
"latitude": "-29.2433828",
"longitude": "-51.199249"
},
"hora": "03:55:00 PM"
},
Some one can help me?
Here is the intere code to your view: https://snack.expo.io/#matheus_cbrl/clusters
I got the follow error:
Device: (3:18096) No cluster with the specified id.
Device: (3:5314) TypeError: t.props.renderMarker is not a function. (In 't.props.renderMarker(e.properties.item)', 't.props.renderMarker' is undefined)
This error is located at:
in e
in MyClusteredMapView
in RCTView
in RCTView
in n
in n
in v
in RCTView
in RCTView
in c
Device: TypeError: t.props.renderMarker is not a function. (In 't.props.renderMarker(e.properties.item)', 't.props.renderMarker' is undefined)
Prettier
Editor
Expo
renderMarker is a function that render just 1 marker. Besides, you use this.state.data for markers but you didn't update it. You could try below
componentDidMount() {
return fetch(
'https://gist.githubusercontent.com/MatheusCbrl/bba7db1c0dbc68be2f26d5c7e15649b6/raw/0fab4ea3b493dcd15e95f172cd0a251724efbc45/ParadasDiurno.json'
)
.then(response => response.json())
.then(responseJson => {
// just setState here e.g.
this.setState({
data: responseJson, <-- update here
isLoading: false,
});
})
.catch(error => {
console.error(error);
});
}
renderCluster = (cluster, onPress) => {
const pointCount = cluster.pointCount,
coordinate = cluster.coordinate;
const clusterId = cluster.clusterId;
return (
<Marker key={clusterId} coordinate={coordinate} onPress={onPress}>
<View style={styles.myClusterStyle}>
<Text style={styles.myClusterTextStyle}>
{pointCount}
</Text>
</View>
</Marker>
);
};
renderMarker(marker) {
console.log('Location picker Marker', marker.location);
const coords = {
latitude: parseFloat(marker.location.latitude),
longitude: parseFloat(marker.location.longitude),
}
return (
<Marker
key={marker.id}
title={'Parada'}
description={marker.hora}
pinColor={'tomato'}
coordinate={coords}
/>
);
}
render() {
return (
<View style={{ flex: 1 }}>
<StatusBar hidden />
<ClusteredMapView
style={{ flex: 1 }}
data={this.state.data}
initialRegion={INIT_REGION}
ref={r => this.map = r}
renderMarker={this.renderMarker}
renderCluster={this.renderCluster}
/>
</View>
);
}

Why there is keys with same value on my React Native FlatList?

It's not always that I get this warning about keys with same value, but it's frequently. Most of the time it happens at the first search.
Here is my code:
const ITEMS_PER_PAGE = 5
export default class SearchForm extends Component {
state = {
allStates: [],
states: [],
page: 1,
displayStatesList: false,
}
componentDidMount = async () => {
await fetch('https://servicodados.ibge.gov.br/api/v1/localidades/estados', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
.then(res => res.json())
.then(res => this.setState({ allStates: res, states: res.slice(0, ITEMS_PER_PAGE -1) }))
}
updateSearch = search => {
let { allStates } = this.state
this.setState({
states: allStates.filter(res => res.nome.includes(search)),
displayStatesList: true,
search: search,
})
}
loadMore = () => {
const { page, states, allStates, search } = this.state
const start = page*ITEMS_PER_PAGE
const end = (page+1)*ITEMS_PER_PAGE-1
const newData = allStates.slice(start, end).filter(res => res.nome.includes(search))
console.log(allStates.length)
this.setState({
states: [...states, ...newData],
page: page + 1,
})
}
selectItem = (nome) => {
console.log('press', nome)
this.setState({
search: nome,
displayStatesList: false,
})
}
renderItem = ({ item }) => {
return (
<View>
<ListItem
title={item.nome}
onPress={() => this.selectItem(item.nome)}
/>
</View>
);
}
render() {
const {
search,
states,
displayStatesList,
} = this.state
return (
<View style={styles.container}>
<SearchBar
placeholder="Type Here..."
onChangeText={this.updateSearch}
value={search}
lightTheme
/>
<View style={styles.listContainer}>
{displayStatesList && <FlatList
data={states}
keyExtractor={item => item.id.toString()}
renderItem={this.renderItem}
onEndReached={this.loadMore}
onEndReachedThreshold={0.7}
/>}
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
},
listContainer: {
height: 200
},
})
Maybe I'm doing things that aren't recommended and it's causing the error?
Or maybe the .slice is not correct?
Observation: If the API is not working, I can put a json file for testing.
Might be there is duplication in API response or from your side when Adding new data in loadMore method.
You can try changing this keyExtractor={(item,index)=> index.toString()}
and add this to very first component of renderItem key={index} as a prop.
This will make sure that the key provided to each item in `Flatlist' is unique.
Try using this handy function to make sure that there are no duplicates in your array of objects.