I am breaking down a larger post into smaller questions. Please understand I never used Promise before and that I am new to React-Native too. It would be great to get feedback and recommendations on how to setup API calls and handle the data.
How can I dynamically create URLs for API requests? Here's what I am trying to achieve:
Pseudocode
Child
Parent
APIservice.js
Child
class APIservice {
_getStopPoint = (endpoint) => {
return new Promise(function(resolve, reject) {
fetch(endpoint)
.then((response) => response.json())
.then((data) => {
console.log("APIservice StopPoint", data)
resolve(data);
});
});
};
};
module.exports = new APIservice
List.js
Parent
As you can see, the way I setup the endpoint is lame. It's not ideal as the URL is the same. I want to structure something that can receive two variables and build the URL on the go. Something like https://api.tfl.gov.uk/Line/${routeid}/Arrivals/${stationid}
.
If I manage that, how can I pass the API call to the APIservice having only one endpoint that dynamically will change based on the two variables it receives? I am not sure how to differentiate the call in the Promise.all having only "one" URL.
let APIservice = require('./APIservice')
let endpoint = 'https://api.tfl.gov.uk/Line/55/Arrivals/490004936E'
let endpoint1 = 'https://api.tfl.gov.uk/Line/Northern/Arrivals/940GZZLUODS'
export class List extends Component {
constructor(props) {
super(props);
this.state = {
bus: null,
tube: null,
}
};
componentWillMount() {
let loadData = (endPoint) => {
Promise.all([
APIservice._getStopPoint(endpoint),
APIservice._getStopPoint(endpoint1),
])
.then((data) => {
// Name for better identification
const listBus = data[0]
const listTube = data[1]
this.setState({
bus: listBus,
tube: listTube
}, () => {
console.log("bus", this.state.bus, "tube", this.state.tube)
});
})
.catch((error) => {
console.log(error)
})
}
loadData(endpoint);
loadData(endpoint1);
}
render() {
return(
<View>
<FlatList
data={this.state.bus}
renderItem={({item}) => (
<Text>{item.timeToStation}</ Text>
)}
keyExtractor={item => item.id}
/>
<FlatList
data={this.state.tube}
renderItem={({item}) => (
<Text>{item.timeToStation}</ Text>
)}
keyExtractor={item => item.id}
/>
</ View>
);
}
};
It is pretty easy to implement what you are saying once you understand how this works.
You are using fetch
for your API calls which returns a Promise
upon use. The pseudo-code for your use case would be something like this:
class APIService {
static fetchFirst(cb) {
fetch('FIRST_URL')
.then(resp => {
try {
resp = JSON.parse(resp._bodyText);
cb(resp);
} catch(e) {
cb(e);
}
})
.catch(e => cb(e));
}
static fetchSecond(routeid, stationid, cb) {
fetch(`https://api.tfl.gov.uk/Line/${routeid}/Arrivals/${stationid}`)
.then(resp => {
try {
resp = JSON.parse(resp._bodyText);
cb(resp);
} catch(e) {
cb(e);
}
})
.catch(e => cb(e));
}
}
module.exports = APIService;
Include this in your parent component and use it as follows:
let APIService = require('./APIService')
export class List extends Component {
constructor(props) {
super(props);
this.state = {
bus: null,
tube: null,
}
};
componentWillMount() {
APIService.fetchFirst((resp1) => {
APIService.fetchSecond(resp1.routeid, resp1.stationid, (resp2) => {
this.setState({
tube: resp2
});
});
});
}
render() {
return(
<View>
<FlatList
data={this.state.bus}
renderItem={({item}) => (
<Text>{item.timeToStation}</ Text>
)}
keyExtractor={item => item.id}
/>
<FlatList
data={this.state.tube}
renderItem={({item}) => (
<Text>{item.timeToStation}</ Text>
)}
keyExtractor={item => item.id}
/>
</ View>
);
}
};
I haven't checked the errors on the callback function, please see that the errors are handled when you use this.