最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Fetch API returning old data in react native - Stack Overflow

programmeradmin4浏览0评论

Description: I'm making a react native app, where I have a list of github users that I'm following and I want to implement the functionality to unfollow and refresh the list.

I made two asynchronous helpers to interact with the github API, one to unfollow the user(via PUT) and another one to get the list of followings(via GET). I also added a firebase listener in the list of followings ponent. Each following would navigate me to an individual profile view consisted of a unfollow button. When I click a button, it should unfollow the user, update the list of followings in the ponent and then navigate back to the list of followings ponent.

Problem Unfollowing the user is working as expected, but the list of followings view still contains the old list. My code is returning back the old data, even though the github api is returning the new updated data, so I'm suspecting the problem must be the way I'm using async/await.

I even made a refresh button to refresh the list of followings, but the new data only gets returned sometimes, like 1/20 times.

UPDATE: After testing multiple scenarios, I don't think firebase is the problem since fetch is returning the same old data. I think the main problem might lie in the fetch call. I've tested grabbing the data from Postman as well and it grabs the correct data.

It seems like fetch is not working as expected since response.json() contains the old data. I've made a simple jsfiddle here (you need to supply your own access token) that shows get_following -> unfollow -> get_following working successfully, aka the following data are modified. However, in my app the fetch returns the same old following data before the unfollow even though the github website UI shows the change and Postman returns the new modified data. I've also updated the code a little bit.

Code

List of followings

    /**
     * Listens for any changes on the database and updates the
     * dataSource accordingly.
     * @param {Firebase Object} ref
     */
    _listenForData(ref) {
        ref.on('value', (snapshot) => {
            this.setState({
                dataSource: snapshot.val()
            },
            this.setState({
                isLoading: false,
            }));
        });
    }

    ponentDidMount() {
        // Sets up the listener for realtime changes.
        GithubApi.get_followings(this.ref)
        .then(_ => this._listenForData(this.ref));
    }

Individual User with unfollow button

async unfollow() {

    try {
        let success = await GithubApi.unfollow_user(this.state.login);
        console.log('unfollowed user');
        console.log(success);
        if (success) {
            // Updates database after unfollowing
            console.log('update followings')
            await GithubApi.get_followings(this.ref);
            return true;
        }
    } catch (error) {
        console.error(error);
        return false;
    }
}

render() {
    const { goBack } = this.props.navigation;
    return (
        <Button
            title='Unfollow'
            onPress={
                () => this.unfollow().then(_ => goBack())
            }
        />
    )
}

Github Api Helpers

const GithubApi = {
    url: '/',
    access_token: ...,

    /**
     * An asychronous helper function to grab data from github
     * given an url and add data the firebase.
     *
     * @param {string} url
     * @param {Firebase Object} firebaseRef
     */
    _get_data_from_github_with_firebase: async function(url, firebaseRef) {
        try {
            let response = await fetch(url);
            let responseStatus = await response.status;
            let responseJson = await response.json();
            if (responseStatus === 200) {
                firebaseRef.set(responseJson,
                (error) => {
                    if (error) {
                        console.log(error);
                        return false;
                    } else {
                        return true;
                    }
                });
            }
            return false;
        } catch (error) {
            return false;
        }
    },

     /**
     * Gets the user's following data and adds it to the database.
     * @param {Firebase Object} firebaseRef
     */
    get_followings: async function(firebaseRef) {
        return await this._get_data_from_github_with_firebase(
            this.url + 'user/following?' + this.access_token,
            firebaseRef
        );
    },

    unfollow_user: async function(username) {
        try {
            let url = this.url + 'user/following/' + username + '?' + this.access_token;
            let response = await fetch(url, { method: 'DELETE'});
            let responseStatus = await response.status;
            if (responseStatus === 204) {
                return true;
            }
            return false;
        } catch (error) {
            return false;
        }
    },

Description: I'm making a react native app, where I have a list of github users that I'm following and I want to implement the functionality to unfollow and refresh the list.

I made two asynchronous helpers to interact with the github API, one to unfollow the user(via PUT) and another one to get the list of followings(via GET). I also added a firebase listener in the list of followings ponent. Each following would navigate me to an individual profile view consisted of a unfollow button. When I click a button, it should unfollow the user, update the list of followings in the ponent and then navigate back to the list of followings ponent.

Problem Unfollowing the user is working as expected, but the list of followings view still contains the old list. My code is returning back the old data, even though the github api is returning the new updated data, so I'm suspecting the problem must be the way I'm using async/await.

I even made a refresh button to refresh the list of followings, but the new data only gets returned sometimes, like 1/20 times.

UPDATE: After testing multiple scenarios, I don't think firebase is the problem since fetch is returning the same old data. I think the main problem might lie in the fetch call. I've tested grabbing the data from Postman as well and it grabs the correct data.

It seems like fetch is not working as expected since response.json() contains the old data. I've made a simple jsfiddle here (you need to supply your own access token) that shows get_following -> unfollow -> get_following working successfully, aka the following data are modified. However, in my app the fetch returns the same old following data before the unfollow even though the github website UI shows the change and Postman returns the new modified data. I've also updated the code a little bit.

Code

List of followings

    /**
     * Listens for any changes on the database and updates the
     * dataSource accordingly.
     * @param {Firebase Object} ref
     */
    _listenForData(ref) {
        ref.on('value', (snapshot) => {
            this.setState({
                dataSource: snapshot.val()
            },
            this.setState({
                isLoading: false,
            }));
        });
    }

    ponentDidMount() {
        // Sets up the listener for realtime changes.
        GithubApi.get_followings(this.ref)
        .then(_ => this._listenForData(this.ref));
    }

Individual User with unfollow button

async unfollow() {

    try {
        let success = await GithubApi.unfollow_user(this.state.login);
        console.log('unfollowed user');
        console.log(success);
        if (success) {
            // Updates database after unfollowing
            console.log('update followings')
            await GithubApi.get_followings(this.ref);
            return true;
        }
    } catch (error) {
        console.error(error);
        return false;
    }
}

render() {
    const { goBack } = this.props.navigation;
    return (
        <Button
            title='Unfollow'
            onPress={
                () => this.unfollow().then(_ => goBack())
            }
        />
    )
}

Github Api Helpers

const GithubApi = {
    url: 'https://api.github./',
    access_token: ...,

    /**
     * An asychronous helper function to grab data from github
     * given an url and add data the firebase.
     *
     * @param {string} url
     * @param {Firebase Object} firebaseRef
     */
    _get_data_from_github_with_firebase: async function(url, firebaseRef) {
        try {
            let response = await fetch(url);
            let responseStatus = await response.status;
            let responseJson = await response.json();
            if (responseStatus === 200) {
                firebaseRef.set(responseJson,
                (error) => {
                    if (error) {
                        console.log(error);
                        return false;
                    } else {
                        return true;
                    }
                });
            }
            return false;
        } catch (error) {
            return false;
        }
    },

     /**
     * Gets the user's following data and adds it to the database.
     * @param {Firebase Object} firebaseRef
     */
    get_followings: async function(firebaseRef) {
        return await this._get_data_from_github_with_firebase(
            this.url + 'user/following?' + this.access_token,
            firebaseRef
        );
    },

    unfollow_user: async function(username) {
        try {
            let url = this.url + 'user/following/' + username + '?' + this.access_token;
            let response = await fetch(url, { method: 'DELETE'});
            let responseStatus = await response.status;
            if (responseStatus === 204) {
                return true;
            }
            return false;
        } catch (error) {
            return false;
        }
    },
Share Improve this question edited Oct 30, 2017 at 8:44 ygongdev asked Oct 29, 2017 at 1:44 ygongdevygongdev 2843 silver badges19 bronze badges 10
  • What does GithubApi.unfollow_user() look like? / What is this.state.login? – Arman Charan Commented Oct 29, 2017 at 2:42
  • @ArmanCharan, sorry I just updated the the code snippet to include unfollower_user. this.state.login is just the user's github login username. – ygongdev Commented Oct 29, 2017 at 2:47
  • All good bro. Did you mean to define your GithubApi object as a Class? I've never really seen anyone call this on an object like that before. – Arman Charan Commented Oct 29, 2017 at 2:48
  • You might also like to try template literals for constructing your HTTP requests. – Arman Charan Commented Oct 29, 2017 at 2:49
  • Yeah, I'm definitely going to refactor later. I'm just trying to solve this problem atm. – ygongdev Commented Oct 29, 2017 at 2:52
 |  Show 5 more ments

3 Answers 3

Reset to default 9

Try this:

let response = await fetch(url, {
  headers: {
    'Cache-Control': 'no-cache'
  }
});

You are missing await inside _get_data_from_github_with_firebase. Try changing the function to this:

_get_data_from_github_with_firebase: async function(url, firebaseRef) {
        try {
            let response = await fetch(url);
            let responseStatus = await response.status;
            let responseJson = await response.json();
            var result = false
            if (responseStatus === 200) {
                result = await firebaseRef.set(responseJson,
                (error) => {
                    if (error) {
                        console.log(error);
                        return false;
                    } else {
                        return true;
                    }
                });
            }
            return result;
        } catch (error) {
            return false;
        }
    },

Note I highly remend you use redux-saga for synchronising actions.

Are you by any chance a former C developer? Or you are used to pass variables by reference?

I think your problem is that inside this function you are trying to return a value by reference:

_get_data_from_github_with_firebase: async function(url, firebaseRef) {
        try {
            let response = await fetch(url);
            let responseStatus = await response.status;
            let responseJson = await response.json();
            var result = false
            if (responseStatus === 200) {
                result = await firebaseRef.set(responseJson,  //You are executing a method by reference
                (error) => {
                    if (error) {
                        console.log(error);
                        return false;
                    } else {
                        return true;
                    }
                });
            }
            return result;
        } catch (error) {
            return false;
        }
    },

Perhaps a more expert JS developer could confirm if this would work but I am not used to do this. I would change the signature and just return the responseJson instead of trying to setting it like this.

Probably responseJson has a value inside this function but is undefined outside.

发布评论

评论列表(0)

  1. 暂无评论