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 isthis.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 callthis
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
3 Answers
Reset to default 9Try 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.