Fetch someUrl.html not working in React Native / Expo? - react-native

I'm trying to use fetch to get the contents of the HTML page in React Native, and I'm running it on expo, here:
https://snack.expo.io/#abalja/hellofetch
Basically the code is nothing special, uses 'fetch' which does work for loading .json files, but I can't get it to work for .html files. It just silently fails, and I don't even get an error logged. I'm not sure if this is Expo or ReactNative issue.
const url2 = 'http://www.spiegel.de/sport/fussball/nations-league-italien-trifft-in-der-nachspielzeit-polen-steigt-ab-a-1233219.html#ref=rss'
export default class App extends React.Component {
componentDidMount(){
console.log('did mount, fetching: ' + url2)
fetch(url2)
.then((response) => {
console.log(response) // 1
return response.text()
})
.then((responseText) => {
console.log('fetch text', responseText) // 2
// return responseText.movies;
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<View style={styles.container}>
</View>
);
}
}
At 1 I get the response logged:
{type:"default",status:200,ok:true,headers:{…},url:"http://www.spiegel.de/sport/fussball/nations-league-italien-trifft-in-der-nachspielzeit-polen-steigt-ab-a-1233219.html",_bodyInit:{…},_bodyBlob:{…}}
type:"default"
status:200
ok:true
►headers:{map:{…}}
url:"http://www.spiegel.de/sport/fussball/nations-league-italien-trifft-in-der-nachspielzeit-polen-steigt-ab-a-1233219.html"
►_bodyInit:{_data:{…}}
►_bodyBlob:{_data:{…}}
At 2 I get absolutely nothing logged.

Promise syntax is confusing to me, so I changed into async-await:
async componentDidMount() {
console.log('did mount, fetching: ' + url2);
try {
let response = await fetch(url2);
let text = await response.text();
console.log(text)
} catch(e) {
console.log(e)
}
}
It works! You can check it here: https://snack.expo.io/#aazwar/fetch-url

It's because you are parsing your Response as text and not as json, and then trying to call object-key against string. Basically what you have at that point is string which looks like json. Parse your response with .json()-method instead.
return response.text() should be therefore return response.json()
to reconstruct your code
// With .then()
fetch(url2)
.then((response) => {
return response.json()
})
.then((responseJson) => {
return responseJson.movies;
})
.catch((error) => {
console.error(error);
});
// OR with await/async
const response = await fetch(url2)
const json = await response.json() // As '.json()' is async function as well
return json.movies
I would succest using await/async since syntax is much more cleaner and it start's to be way to go.

Related

React Hook does not set on first API call

So I am sure I am messing something up, but I am not super skilled at API.
So I am trying to make an API call to check if the user exists, if user exists then move about business, if not then do other stuff.
So my first call gets the data, and the user DOES exist, the hook is setting to true, however in my log it fails and the next API is ran. However if I do it a 2nd time, it is true...
What am I doing wrong.
const handleSubmit = async () => {
const data = await axios
.get(`URL`, {
})
.then((resp) => {
if (resp.data.user.name) {
setCheckUser(true);
console.log(resp.data.user.name);
}
return data;
})
.catch((err) => {
// Handle Error Here
console.error(err);
});
console.log(checkUser);
if (!checkUser) {
console.log('No User Found');
//Do Stuff//
}
};
I think the problem here is that setCheckUser(true) is an async operation, so there is no guarantee that the checkUser variable will turn to true right away.
Maybe you can solve this by using a useEffect block like this
//somewhere on the top of your file, below your useState statements
useEffect(()=> {
if (!checkUser) {
console.log('No User Found');
//Do Stuff//
}
}, [checkUser])
const handleSubmit = async () => {
const data = await axios
.get(`URL`, {
})
.then((resp) => {
if (resp.data.user.name) {
setCheckUser(true);
console.log(resp.data.user.name);
}
return data;
})
.catch((err) => {
// Handle Error Here
console.error(err);
});
};

Question reg expo FileSystem.readAsStringAsync

I'm pretty new to react native and need some help reg. the possiblity to read an image from a file (like an image). I'm using the expo filesystem library with the following code:
const uploadImages = (file) => {
let data = null;
try {
data = await FileSystem.readAsStringAsync(file);
console.log(data)
} catch (err) {
console.log(err)
}
The issue I have is that I get: 'await' is only allowed within async functions
How can I call this function to wait until the data is loaded into the data variable ?
FileSystem.readAsStringAsync(...) returns Promise.
You can use Promise api like .then() and .catch():
const uploadImages = (file) => {
FileSystem.readAsStringAsync(file)
.then(data => {
// Do something with your data in this block
console.log(data);
})
.catch(err => {
console.log(err.message)
})
}

How to add navigation function inside async function?

I have created an async function that fetches data from api and turns red, whenever the icon is presses, however now I want just after the like function is completed it navigates to another page, however am not able to do it.
Kindly help,
Below is the way that I had tried,
onButtonPress = async(item) => {
console.log(item)
console.log(this.state.buttonColor,'hello')
if(!this.state.likedItemIds.includes(item._id)){
try {
const response = await fetch("some url"+item._id);
const resJson = await response.text();
this.setState(prevState => ({
likedItemIds: [...prevState.likedItemIds, item._id]
}))
console.log(resJson)
if(this.state.buttonColor!=='white'){
this.props.navigation.navigate('Wishlist')
}
}
catch (error) {
console.error(error);
}
}
Do tell me if anything else is required and kindly help.
setState is an asynchronous function that allows you to pass a callback as the second argument. So you can do your navigation in that callback, which will fire after setState is complete. This means you will navigate away from the page once the like is complete.
You can do the below:
onButtonPress = async(item) => {
console.log(item)
console.log(this.state.buttonColor,'hello')
if(!this.state.likedItemIds.includes(item._id)){
try {
const response = await fetch("some url"+item._id);
const resJson = await response.text();
this.setState(prevState => ({
likedItemIds: [...prevState.likedItemIds, item._id]
}), () => {
// Do whatever else you need to do here (validation, etc.)
this.props.navigation.navigate('Wishlist')
})
}
catch (error) {
console.error(error);
}
}

React Native fetch doesn't work in another fetch callback

If I call my api function from POINT 1, fetch method inside the api method works well. When I comment it out and call the function at POINT 2 fetch method inside the addAccount() doesn't work. There is no exception, no rejection, no request on Reactotron, even I can't find request over Charles Proxy. What is the difference and what I have to know to figure it out?
I tried with RN 0.55.2 and 0.57.5
// Auth.js typical react native component
import * as api from '../actions/api';
class Auth extends Component {
// first triggered function
loginAccount(){
// api.addAccount(); // POINT 1 - this line works well if I uncomment
fetch('https://domain-a.com/login/',{
method: 'POST',
credentials: "same-origin",
headers: {
'accept-language': 'en-US;q=1',
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: encodeURIComponent(bodyParameters)
}).then((response) => {
console.log(response);
return response.json()
}).then(({ status, invalid_credentials }) => {
if(status == "ok"){
CookieManager.get('https://domain-a.com')
.then((cookies) => {
this.fetchAccountData(cookies);
})
})
}
fetchAccountData(cookies){
fetch('https://domain-a.com/'+cookies.user_id+'/info/',{
method: 'GET',
headers: {
'cookie': cookies
}
}).then((response) => {
return response.json();
})
.then(({ user, status }) => {
api.addAccount(); // POINT 2 - this line doesn't work
});
}
}
// api.js
// I repleaced fetch code with document example just to be clearify
export const addAccount = () => {
console.log("fetch begin"); // always works
fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson); // won't works from point 2
})
.catch((error) =>{
console.error(error); // never runs
});
}
It looks like your first .then statement in the addAccount() function is missing a return statement. responseJson would be undefined without a proper a 'return response.json()' statement. Also adding brackets for better semantic formatting.
export const addAccount = () => {
console.log("fetch begin"); // always works
fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => {
console.log(response); //test this response
return response.json();
})
.then((responseJson) => {
console.log(responseJson); // won't works from point 2
})
.catch((error) =>{
console.error(error); // never runs
});
}

Parsing JSON in React Native fetch method doesnt work

Im trying to call an API with fetch from React Native App but itdoesnt log the response data (console.warn('data', data)) for some reason. It prints the 'call to getArtists' log but then nothing happens.
const URL = 'https://jsonplaceholder.typicode.com/posts'
function getArtists(){
console.log('call to getArtists')
return fetch(URL)
.then(response => response.json())
.then(data => {
console.warn('data', data)
})
}
Code is available here: https://snack.expo.io/rkzea2Zlm at components/api-client.js
What am I doing wrong?
First in your "api_client.js", put a return inside like the code bellow.
function getArtists(){
console.log('call to getArtists')
return fetch(URL)
.then(response => response.json())
.then(data => {
return data
})
}
In your App.js just do that inside componentWillMount.
componentDidMount(){
getArtists()
.then(data => {
alert(JSON.stringify(data))
});
}