Displaying MapView markers from JSON API - json

I am using React Native map view (https://github.com/react-native-community/react-native-maps) and have successfully got my map to display with manual markers. However, when I try to display my fetched JSON data markers I get constant syntax errors.
import MapView from 'react-native-maps'
import { Marker } from 'react-native-maps';
constructor(props) {
super(props);
this.state = {
myMarkers: []
};
}
componentDidMount() {
this.getMarkers();
}
getMarkers() {
axios
.get("MYAPISOURCE")
.then(response => {
this.setState({
myMarkers: response.data.responser
});
});
}
render() {
return (
<MapView style={styles.map}
rotateEnabled={false}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.04,
longitudeDelta: 0.05,
}}
>
{this.state.myMarkers.map((post, index)=> {
<MapView.Marker
key={post.ID}
coordinate={{
latitude:{post.lat},
longitude:{post.lng}}}
/>
})}
</MapView>
);
}
My Map View code which keeps getting syntax error: Unexpected tokens, expected "," in the coordinate function. I have tried so many different options but I cannot get the markers and map to work when I have my marker code.
HOWEVER If I run this code below outside of MapView, it successfully displays my data so my API call and myMarkers state is working and has the proper data:
{this.state.myMarkers.map((post, index)=> {
return (
<View key={index}>
<Text>
{post.lat},
{post.lat}
</Text>
</View>
)
})}
This displays the following:
37.78825, -122.4324
33.78825, -121.4324
31.78825, -124.4324

The data from the service is coming after the rendering(after the components render with empty values) so you need to use promise with state to render it once its ready.
examble:-
constructor(){
super(props);
this.state={dataIsHere:false};
}
dataSource()=>{
axios.<><><>.then((data)=>this.setState({dataIsHere:true}));
}
render(){
return(
...
//It will render markers once the data is ready
{this.state.dataIsHere?
this.state.myMarkers.map((post, index)=> {
<MapView.Marker
key={post.ID}
coordinate={{
latitude:{post.lat},
longitude:{post.lng}}}
/>
}):null}
...
)
}

Related

React native json parsing through Mysql

I am new to react-native. I need to display my JSON into my react native main page but I am not sure how to. Do you have any suggestions espiclay that the Json file is long. I want to display only "s_title":"hjkjhjk","s_description":"jnkmjhnkl" in an altarntive list view
JSON
Array [
Object {
"fk_c_locale_code": "en_US",
"fk_i_item_id": 3,
"s_description": "jnkmjhnkl",
"s_title": "hjkjhjk",
},
My Main React-Native page is the following where I need it to read from the Json file that:
import {
Button,
Alert
}
HomeScreen.navigationOptions = {
header: null,
};
function test(){
fetch('http://***:3000/users')
.then(response => response.json())
.then(users => console.warn(users));
//Alert.alert(response);
}
The code below that worked. No need for parsing or anything!
The source was the networking info section at react-native page.
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, FlatList} from 'react-native';
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
android:
'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
dataSource:[]
};
}
componentDidMount(){
fetch("http://*****:3000/users")
.then(response => response.json())
.then((responseJson)=> {
this.setState({
dataSource: responseJson
})
})
.catch(error=>console.log(error)) //to catch the errors if any
}
render(){
return(
<View style={{padding:10}}>
<FlatList
padding ={30}
data={this.state.dataSource}
renderItem={({item}) =>
<View style={{height: 50}}>
<Text style={{height: 50}}>{item.s_description}</Text>
<Text style={{height: 50}}>{item.s_title}</Text>
<View style={{height: 1,backgroundColor:'gray'}}></View>
</View>
}
/>
</View>
)}
}
The easiest way would be your jsonobject[0].s_title and jsonobject[0].s_description.
Do check if it is undefined before assigning it; something like:
title = jsonobject[0].s_title === undefined ? "" : jsonobject[0].s_title

Return and render looped text items from XML on React Native in a list

I've found a way to extract items from an XML within ComponentDidMount method and loop them. I also managed to pass them on to the 'render' section of Component and return them as one big wall of strings. But I will need to display them as a list so that one line will be dedicated to one item.
This is my current demo:
https://snack.expo.io/#leourushi/api-looping-00
This is the original XML I’m pulling data from:
https://www.wmata.com/rider_tools/metro_service_status/feeds/mis/rail.xml
And I used this tool to parse XML into readable format:
https://www.npmjs.com/package/react-native-rss-parser
I’m trying to create a list view similar to this one:
https://www.wmata.com/service/status/#lines-affected
I used map function to extract short titles of travel alerts (Yellow Line, Blue Line etc) and more detailed description texts. I stored them into variables named them gimmeNames and gimmeDescriptions respectively.
Now I would like to display them side by side in a list view.
I created empty state names at the top as below.
constructor(props) {
super(props);
this.state = {
rss: [],
gimmeNames: "",
gimmeDescriptions: ""
};
}
Within componentDidMount, I defined the original URL, ran a ‘fetch’ operation and created two loop functions. And I defined the results as gimmeNames and gimmeDescriptions.
componentDidMount() {
var url = 'https://www.wmata.com/rider_tools/metro_service_status/feeds/mis/rail.xml';
return fetch(url)
.then((response) => response.text())
.then((responseData) => rssParser.parse(responseData))
.then((rss) => {
const gimmeNames = rss.items.map(function(item, index) {
return (item.title);
});
const gimmeDescriptions = rss.items.map(function(item, index) {
return (item.description);
});
this.setState({
gimmeNames: gimmeNames,
gimmeDescriptions: gimmeDescriptions,
rss: rss
});
});
}
Here is my attempt to render them side by side. But currently I have one big chunk of ALL the looped title names and another chunk of ALL the description items.
render() {
const { rss, gimmeNames, gimmeDescriptions } = this.state;
return(
<View style={styles.bigContainer}>
<View style={styles.box}>
<Text> Title: Hard coded strings for now </Text>
<View style={styles.lineItem}>
<View style={styles.lineRow}>
<Text style={styles.leftColumn}>{gimmeNames}</Text>
<Text style={styles.rightColumn}>{gimmeDescriptions}</Text>
</View>
</View>
</View>
</View>
)
}
I am definitely doing this wrong. But I don't know how to get to the right answer. Any pointer would be appreciated.
I think this will work. It's similar to other examples that have worked for me before:
constructor(props) {
super(props);
this.state = {
rss: []
};
}
And then when you fetch the data:
componentDidMount() {
var url =
'https://www.wmata.com/rider_tools/metro_service_status/feeds/mis/rail.xml';
return fetch(url)
.then((response) => response.text())
.then((responseData) => rssParser.parse(responseData))
.then((rss) => {
console.log(rss)
this.setState({
rss: rss
});
});
}
And then when you render them:
render() {
const gimmeItems = this.state.rss.items.map((item) =>
<View style={styles.lineItem}>
<View style={styles.lineRow}>
<Text style={styles.leftColumn}>{item.title}</Text>
<Text style={styles.rightColumn}>{item.description}</Text>
</View>
</View>
);
return(
<View style={styles.bigContainer}>
<View style={styles.box}>
<Text> Title: Hard coded strings for now </Text>
{gimmeItems}
</View>
</View>
)
}

React-native: how to get JSON from backend and put the objects in react-native elements, such as Text?

I am trying to fetch JSON data from a php file, which seems to work fine; I can alert values from the JSON. But I want to be able to put these values on the mobile app screen in Text elements or whatever. And I want this to happen when the screen opens, not when a button is pressed. So I made a function that fetches the JSON and I'm trying to return a value in Text elements. This function is called from the rendering. I don't get error messages, but it isn't working. Nothing shows up.
Here is the code:
import React, { Component } from 'react';
import { View, Text, AsyncStorage, Alert } from 'react-native';
import { UsersMap } from '../UsersMap';
import { PrimaryButton } from '../Buttons';
import styles from './styles';
class RestOptions extends Component {
getSearchResults() {
fetch('http://192.168.1.3/Restaurant_App/php/search_results.php')
.then((response) => response.json())
.then((responseJson) => {
var JSON_Test = responseJson["distance"][0];
//Alert.alert(JSON_Test);
return (
<View>
<Text>{JSON_Test}</Text>
</View>
);
}).catch((error) => {
console.error(error);
});
}
setReservation = () => {
this.props.navigation.navigate('SetReservation');
};
render() {
return (
<View>
<UsersMap />
{this.getSearchResults()}
<PrimaryButton
label="Set Reservation"
onPress={() => this.setReservation()}
/>
</View>
);
}
};
export default RestOptions;
This is what happens. The JSON value should appear between the map and the button:
Search Results Screen
First of all, in order to fetch the data as the screen opens, you should use the lifecycle method componentWillMount, which executes before the first render, and then store the result in the component's state. React docs on state and lifecycle
class RestOptions extends Component {
constructor(props) {
super(props);
this.state = {
jsonTest: null
}
}
componentWillMount() {
this.getSearchResults();
}
getSearchResults() {
fetch('http://192.168.1.3/Restaurant_App/php/search_results.php')
.then((response) => response.json())
.then((responseJson) => {
var JSON_Test = responseJson["distance"][0];
//Alert.alert(JSON_Test);
this.setState({ jsonTest: JSON_Test });
}).catch((error) => {
console.error(error);
});
}
//...
Then you can display the value on the render() method:
render() {
return (
<View>
<UsersMap />
<Text>{this.state.jsonTest}</Text>
<PrimaryButton
label="Set Reservation"
onPress={() => this.setReservation()}
/>
</View>
);
}
If the response is an array of values, you can use map() to display each of them in their own Text element:
{this.state.jsonTest.map((value, index) => <Text key={index}>{value}</Text>)}

undefined is not an object

TypeError: undefined is not an object (evaluating 'this.props.data.map')
appBodyData:
render(){
let articles =this.props.data.map(function(articleData,index) {
return (
<Card>
<CardItem>
<Body>
<Text>
{articleData.address.city}
</Text>
</Body>
</CardItem>
</Card>
)
});
return (
<Content>
{articles}
</Content>
);
}
**[appBody:][1]**
getData(){
return fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((responseJson) => {
this.setState({data:responseJson.array});
})
.catch((error) => {
console.error(error);
});
}
componentDidMount(){
this.getData();
}
render() {
return (
<AppBodyData data={this.state.data}/>
);
}
This error is shown When I am trying run in emulator.
How can i fix this error.
It seems the map function is not able to get data.
react native cli version :50
sdk version:23
Because your fetch is async, at the time of the first render this.props.data is undefined.
Additionally, you need to use this.state.data since the result of the fetch is setting the state not props
set inital state in constructor first:
constructor(props) {
super(props);
this.state = {
data: []
}
}
and then change to state
let articles =this.state.data.map(function(articleData,index) {
you are getting null value due to fetch method it take time to fetch data so render in if condition
render(){
return (
<Content>
{this.props.data?this.props.data.map((articleData,index)=>{
return <Card>
<CardItem>
<Body>
<Text>
{articleData.address.city}
</Text>
</Body>
</CardItem>
</Card>
}):null}
</Content>
);
}

React-google-maps re-rendering issue

I'm having some issues with the react-google-maps npm module.
First render, works like a charm.
When re-rendering the map-component i get the classic google-maps error.
Uncaught TypeError: Cannot read property 'offsetWidth' of null
Uncaught (in promise) TypeError: Cannot read property 'componentWillReceiveProps' of null(…)
Because the map object isn't available when rendering?
My google-maps Map Component
import React, { PropTypes } from 'react'
import { GoogleMap, Marker, GoogleMapLoader } from 'react-google-maps'
export class Map extends React.Component {
static propTypes = {
coordinates: PropTypes.object,
markers: PropTypes.array
};
render () {
return (<section onloadstyle={{height: '300px'}}>
<GoogleMapLoader
containerElement={
<div
{...this.props}
style={{
height: '300px',
width: '100%'
}}
/>
}
googleMapElement={
<GoogleMap
ref={(map) => console.log(map)}
defaultZoom={15}
defaultCenter={this.props.coordinates}>
{this.props.markers.map((marker, index) => {
return (
<Marker key={index} {...marker} />
)
})}
</GoogleMap>
}
/>
</section>)
}
}
export default Map
And i use the component like this:
var coordinates = {lat: this.props.item.delivery_address_lat, lng: this.props.item.delivery_address_lng}
var map = this.props.item.delivery_address_lat !== 0 && this.props.item.delivery_address_lng !== 0 ? (<Row id='map'>
<Map markers={[{position: coordinates}]} coordinates={coordinates} />
</Row>) : ''
Is this because the google-maps-react module isn't unmounting the component properly or is it something i've done?
The following is inside head
<script src="https://maps.googleapis.com/maps/api/js?key=MY-KEY"></script>
EDIT
Tried to solve it a non react-redux way and this is by no means a solution since it produces the error message: Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the Map component.
But still, the map re-renders correctly. I tried doing this the redux way of calling passed prop functions & state and set the {map: section} in the state, passing it down from the calling view. Didn't solve a thing and resulted in the same error message, even though it was delayed with setTimeout
Im kind of stuck here, don't know how to solve this.
componentDidMount () {
this.setState({map: null})
setTimeout(() => this.setState({
map: <section onloadstyle={{height: '300px'}}>
<GoogleMapLoader
containerElement={
<div
{...this.props}
style={{
height: '300px',
width: '100%'
}}
/>
}
googleMapElement={
<GoogleMap
ref={(map) => console.log(map)}
defaultZoom={15}
defaultCenter={this.props.coordinates}>
{this.props.markers.map((marker, index) => {
return (
<Marker key={index} {...marker} />
)
})}
</GoogleMap>
}
/>
</section>
}), 300)
}
render () {
if (!this.state) {
return <span />
} else {
return this.state.map
}
}
The solution for the second edit was to clear the setTimeout() call in the componentWillUnmount() function.
You always have to clear intervals & timeouts when the component is unmounting.
componentDidMount () {
this.setState({map: null})
this.timeout = setTimeout(() => this.setState({
map: <section onloadstyle={{height: '300px'}}>
<GoogleMapLoader
containerElement={
<div
{...this.props}
style={{
height: '300px',
width: '100%'
}}
/>
}
googleMapElement={
<GoogleMap
ref={(map) => console.log(map)}
defaultZoom={15}
defaultCenter={this.props.coordinates}>
{this.props.markers.map((marker, index) => {
return (
<Marker key={index} {...marker} />
)
})}
</GoogleMap>
}
/>
</section>
}), 300)
}
componentWillUnmount () {
clearTimeout(this.timeout)
}
render () {
if (!this.state) {
return <span />
} else {
return this.state.map
}
}
This solution isn't a good one and isn't in-line with the react-redux workflow. But it works.