0

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

  • Retrieve two variables
  • Use these two variables to build an URL
  • Trigger the first Promise and resolve
  • Retrieve another two variables
  • Use these two variables to build a new an URL
  • Trigger the second Promise and resolve
  • Gather the data from both promises and pass to parent

Parent

  • Retrieve data from Child
  • Get data from the first Promise and set to a state
  • Get data from the second Promise and set to another state

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>
        );
    }
};
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Diego Oriani
  • 1,647
  • 5
  • 22
  • 31

1 Answers1

1

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.

Jagjot
  • 5,816
  • 2
  • 24
  • 41
  • Ow... BOOM. Okay, I will need to analyse line by line and try to understand what's going on. Regardless, thank you for the reply! – Diego Oriani Feb 23 '18 at 14:00
  • @DiegoOriani Sure! Let me know if you don't understand any piece. I'd love to explain it to a fellow newbie :) – Jagjot Feb 23 '18 at 14:02
  • Okay, let's start easy. What `static` does? I can't find it in the documentation. – Diego Oriani Feb 23 '18 at 14:33
  • @DiegoOriani `static` is a "visibility modifier" in JS. You can look it up anywhere for ex. [here](https://stackoverflow.com/a/5083337/2016306) – Jagjot Feb 23 '18 at 14:37
  • I see... it is a JS thing not fetch. Thank you. Next, I am finding hard to understand where the variables for the second fetch are defined (and how). On my code I am was trying to pass two variables to the first promise such as `55` and `490004936E`, resolve, pass two new variables, `66` and `940GZZLUODS` using the same API call, resolve and pass both sets of data at the same time to the parent. Perhaps my pseudo-code is not clear enough. – Diego Oriani Feb 23 '18 at 14:54
  • @DiegoOriani You can modify the first function in `APIService` and pass your params in that function. – Jagjot Feb 23 '18 at 15:06
  • 1
    Cool, I will try some stuff here. I really appreciate the help. – Diego Oriani Feb 23 '18 at 15:11
  • @DiegoOriani I just re-read your comment and you were asking about the variable for the second fetch function. As per your question you wanted to give variables to the second fetch based on your 1st fetch statement. That is what I have done here. If you'll see `resp1` has the response from 1st fetch and it is being given to the 2nd fetch statement in `componentDidMount` – Jagjot Feb 23 '18 at 16:37
  • I finally understood what's going on. The issue is the actual API response. There is an inconsistency. Thank you very much for your help. On another note, can I ask what `cb` stands for? Is it content blob? Just curious about the acronym. – Diego Oriani Feb 23 '18 at 18:42
  • @DiegoOriani `cb` stands for callback here :) Happy to help! – Jagjot Feb 23 '18 at 19:07
  • how can you execute a function cb (callback) if it is not defined anywhere in the code? Could you explain me that? – Diego Oriani Feb 27 '18 at 07:54
  • @DiegoOriani while calling the API function we give callback function as an argument. That is how it gets defined. – Jagjot Feb 27 '18 at 08:03