Api fetching in react native - using axios - react-native

I am trying to fetch data from API game news.
Link of API: https://rapidapi.com/danielilieprojects-G7QdvK7X5Ao/api/videogames-news2/
I am not getting any data from the API.
It looks like API is giving me infomation in string, so I thnik mybe its problem there.
Any Ideas what is wrong with my code?
API returns this data:
{
"title": "GTA 6 release date rumours, news, and speculation",
"date": "Fri, 03 Feb 2023 17:06:57 +0000",
"description": "Want to know more about the GTA 6 release date? Given how many years it takes to create open worlds of the same calibre as GTA V, it’s no surprise that Rockstar Games has already spent years developing GTA 6. Like most developers, Rockstar prefers to keep its secrets close to its chest until they’re close to the end of development, so we may not see any official GTA 6 gameplay for some time. Early gameplay footage of GTA 6 recently surfaced online, along with lines of source code from the game itself. Rockstar has issued a statement on Twitter which confirms that an unauthorised third party managed to access and download information from their systems, including development footage for the open-world game. However, its statement notes that the developers don’t believe this leak should impact the development of their long-term projects or disrupt their live service games.",
"image": "https://www.pcgamesn.com/wp-content/sites/pcgamesn/2022/02/gta-6-release-date-2022.jpg",
"link": "https://www.pcgamesn.com/grand-theft-auto-vi/gta-6-release-date-setting-map-characters-gameplay-trailers"
}
Games component
import { StyleSheet, SafeAreaView, FlatList } from "react-native";
import axios from "axios";
import { useState, useEffect } from "react";
import Article from "../components/Article";
export default function Games() {
let [articles, setArticles] = useState([]);
const getArticle = () => {
axios
.get({
method: "GET",
url: "https://videogames-news2.p.rapidapi.com/videogames_news/search_news",
params: { query: "GTA" },
headers: {
"X-RapidAPI-Key":
"8114fa0745msh7596481771a0acbp1eb7e4jsnaae758420c49",
"X-RapidAPI-Host": "videogames-news2.p.rapidapi.com",
},
})
.then(function (response) {
setArticles(response.data);
})
.catch(function (error) {
console.log("error", error);
})
.finally(function () {
setLoading(true);
});
};
useEffect(() => {
getArticle();
}, []);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={articles}
renderItem={({ item }) => (
<Article
image={item.image}
title={item.title}
description={item.description}
sourceName={item.source.name}
/>
)}
keyExtractor={(item) => item.title}
/>
</SafeAreaView>
);
}

Axios returns a data object with the response. This is where the your data is stored. To make sure your data is correct you can do a console.log
.then(function (response) {
// console.log(response);
setTitle(response.data[0].item.title);
setArticle(response.data[0].item.description);
})

There are a few issues with your code:
You are using axios.get instead of axios.get method. The correct syntax is axios.get(url, [config]) where url is the URL to access and config is an optional configuration object.
In your response, you are trying to access the data as response[0] but the actual data structure is unknown. You should use response.data to access the data.
You are trying to map title and article directly from the response, but you have not assigned the response data to these state variables correctly. You need to update the state values inside the .then block, like this:
.then(function (response) {
setTitle(response.data);
setArticle(response.data);
}

Related

Referencing JSON object fields after assigning to variable in useEffect()

I'm attempting to retrieve a JSON object from an API call, and then set a useState variable to the response for use in my app. I am able to successfully receive the JSON response, but if I try to reference specific fields I get an error saying
null is not an object (evaluating data.type). I understand that this happens because initially the data variable is simply null, but I'm not sure the best way to go about preventing this and I suspect I'm doing something fundamentally wrong.
Here's the function which queries the API and retrieves the response data:
export function searchFlightOffers(postData) {
return getAmadeusToken().then(data => {
const config = {
headers: {
'Authorization': `Bearer ${data.access_token}`
}
}
return axios.post("https://test.api.amadeus.com/v2/shopping/flight-offers", postData, config).then(data => data);
});
}
Then the React Native function which uses it
export default function FlightScreen() {
const [flightResponse, setFlightResponse] = useState(null);
useEffect(() => {
searchFlightOffers(postData).then(data => setFlightResponse(data.data));
}, [])
console.log("TEST: ", flightResponse.type);
Is there a more efficient way I should be doing this?
EDIT: To add hopefully a more clear description of the issue, here's the JSX I'm trying to use this data in:
return (
<ScrollView style={{marginTop: 220}}>
{
flightResponse != null ? flightResponse.map(data => {
return (
<FlightCard
key={data.id}
data={data}
onPress={() => {}}
/>
)
}) : false
}
</ScrollView>
If I add a conditional which checks to see if the flightResponse data is null and then map the data if not then this works just fine. Removing the conditional and just leaving it like this:
return (
<ScrollView style={{marginTop: 220}}>
{
flightResponse.map(data => {
return (
<FlightCard
key={data.id}
data={data}
onPress={() => {}}
/>
)
})
}
</ScrollView>
Leaves me with this error: null is not an object (evaluating 'flightResponse.map') .
While technically the conditional is a solution to my problem there must be a cleaner way to handle this no?
Update: A solution to this problem is to change
const [flightResponse, setFlightResponse] = useState(null);
to
const [flightResponse, setFlightResponse] = useState([]);
and then I can remove the conditional from the JSX.
My apology that I didn't see the additional info you have put there. Apparently you have resolved this issue on your own by adding the check for null, which, to my knowledge, is the correct usage pattern.
You have to check for null because the code in useEffect is not guaranteed to complete (because it is async) before react native executes the code to render the components. By checking for null, you place a guard on this exact situation (and other situations, such as error during fetching data, data itself is empty, etc.).
Original answer (obsolete)
Try rewrite your searchFlightOffers function in async/await style. This way, it is clearer what object is returned. I suspect your current version does not return the data.
The rewrite can be something like this (untested, use with caution).
export const searchFlightOffers = async (postData) => {
try {
const token = await getAmadeusToken();
} catch (err) {
// handle error during token acquisition
console.log(err);
}
const config = {
headers: {
'Authorization': `Bearer ${token.access_token}`
}
}
try {
const flightOfferData = await axios.post(
"https://test.api.amadeus.com/v2/shopping/flight-offers",
postData,
config,
);
return flightOfferData;
} catch (err) {
// handle error during flight offer acquisition
console.log(err);
}
}

Getting the Plaid Link to Work in my Create React App with Auth0

I had started a project a little while ago and have been busy lately so I have not been able to work on it. I am out of practice with web development because I had recently joined the military. Right now the project consists of a create-react-app app with auth0 integrated. What I am trying to do is get the plaid link integrated into the page it takes you after logging in using auth0. I am requesting help on what code from the plaid docs I use in order for this to work. Their documentation is a little confusing to me, maybe because I'm so out of practice. Any help would be much much appreciated.
https://github.com/CollinChiz/SeeMyCash
Have you taken a look at the Quickstart at https://github.com/plaid/quickstart/? It contains a full React implementation that does this. Here's the relevant excerpt:
// APP COMPONENT
// Upon rendering of App component, make a request to create and
// obtain a link token to be used in the Link component
import React, { useEffect, useState } from 'react';
import { usePlaidLink } from 'react-plaid-link';
const App = () => {
const [linkToken, setLinkToken] = useState(null);
const generateToken = async () => {
const response = await fetch('/api/create_link_token', {
method: 'POST',
});
const data = await response.json();
setLinkToken(data.link_token);
};
useEffect(() => {
generateToken();
}, []);
return linkToken != null ? <Link linkToken={linkToken} /> : <></>;
};
// LINK COMPONENT
// Use Plaid Link and pass link token and onSuccess function
// in configuration to initialize Plaid Link
interface LinkProps {
linkToken: string | null;
}
const Link: React.FC<LinkProps> = (props: LinkProps) => {
const onSuccess = React.useCallback((public_token, metadata) => {
// send public_token to server
const response = fetch('/api/set_access_token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ public_token }),
});
// Handle response ...
}, []);
const config: Parameters<typeof usePlaidLink>[0] = {
token: props.linkToken!,
onSuccess,
};
const { open, ready } = usePlaidLink(config);
return (
<button onClick={() => open()} disabled={!ready}>
Link account
</button>
);
};
export default App;

Nuxt.js - The best place for API calls

I'm new to Vue.js Nuxt and all front-end stuff.
I have a question about API calls. I'm not sure what is the right way, the best practice here.
I have a store. In that store, I have actions that are calling my API and sets state eg.
async fetchArticle({ state, commit }, uuid) {
const response = await this.$axios.get(`articles/${uuid}/`)
commit('SET_ARTICLE', response.data)
},
And that is fine it is working for one component.
But what if I want to just fetch the article and not changing the state.
To be DRY first thing that comes to my mind is to create the service layer that is fetching the data and is used where it is needed.
Is it the right approach? Where can I find some real-world examples that I can take inspiration from?
Using the repository pattern to abstract your API is definitely a good idea! Whether you use the #nuxtjs/axios module or the #nuxt/http module, you can pass either instance to your repository class/function. Below a real world example of an abstracted "repository.js" file.
export default $axios => resource => ({
index() {
return $axios.$get(`/${resource}`)
},
create(payload) {
return $axios.$post(`/${resource}`, payload)
},
show(id) {
return $axios.$get(`/${resource}/${id}`)
},
update(payload, id) {
return $axios.$put(`/${resource}/${id}`, payload)
},
delete(id) {
return $axios.$delete(`/${resource}/${id}`)
}
})
You can then create a plugin to initialize all different kinds of repositories for your endpoints:
import createRepository from '~/path/to/repository.js'
export default (ctx, inject) => {
const repositoryWithAxios = createRepository(ctx.$axios)
const repositories = {
posts: repositoryWithAxios('posts'),
users: repositoryWithAxios('users')
//...
}
inject('repositories', repositories)
}
Further read: Organize and decouple your API calls in Nuxt.js
I will an example of a service layer implementation for my portfolio to create my dashboard that shows some statics about my github and stackoverflow profiles, to do this i created a folder called services inside the project root :
pages
services
|_AxiosConfig.js
|_GitHubService.js
|_StackoverflowService.js
...
in the AxiosConfig.js file i put i created an axios instance with its configuration :
import axios from 'axios';
const clientAPI = url =>
axios.create({
baseURL: url,
withCredentials: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
export default clientAPI;
then in my GitHubService.js i imported that axios instance called clientAPI which i used to my requests :
import clientAPI from './AxiosConfig';
const baseURL = 'https://api.github.com';
export default {
getUser(name) {
return clientAPI(baseURL).get('/users/' + name);
},
getRepos(name){
return clientAPI(baseURL).get('/users/' + name+'/repos');
},
getEvents(name,page){
return clientAPI(baseURL).get('/users/' + name+'/events?per_page=100&page='+page);
},
getLastYearCommits(name,repo){
return clientAPI(baseURL).get('/repos/' + name+'/'+repo+'/stats/commit_activity');
}
};
then in my page i used asyncData hook to fetch my data :
import GitHubService from '../../services/GitHubService'
export default {
...
async asyncData({ error }) {
try {
const { data } = await GitHubService.getUser("boussadjra");
const resRepos = await GitHubService.getRepos("boussadjra");
return {
user: data,
repos: resRepos.data
};
} catch (e) {
error({
statusCode: 503,
message: "We cannot find the user"
});
}
}
I wanted to use axios in my service/service.js file, so instead of passing axios, I accessed it directly like this:
export default {
async fetchArticle() {
let response = await $nuxt.$axios.$get('/api-url')
return response
},
}
In Nuxt, if you want to just get the data without keeping it in your store, you could use the asyncData function, which asynchronously loads data (from API calls and the like) and pushes it into the component's data object before rendering.

React native implement Youtube data API v3

Is it possible somehow to integrate youtube data API v3 directly in react-native?
If not, Is there any other way to do it?
Right now I am using axios to send get request but not able to figure out how exactly send the request what I tried is this:
componentWillMount() {
axios.get('https://www.googleapis.com/youtube/v3/channels', {
params: {
'id': 'UC_x5XG1OV2P6uZZ5FSM9Ttw',
'key': 'AIzaSy...',
'part': 'snippet,contentDetails,statistics'
}
}).then(
(response) => {
console.warn(response);
}).catch(
(error) => {
console.error(error);
});
}
Not sure whether it is correct or not as I don't have much experience in React native. Any help would be appreciated.
You could probably use packages like youtube-search or youtube-api-searchfor your purpose.
The call with the latter one looks like this:
import YTSearch from 'youtube-api-search';
YTSearch({ key: YOUR_API_KEY, term: YOUR_SEARCH_STRING }, result => {
console.log(result);
});

Why is it considered poor practice to use Axios or HTTP calls in components?

In this article, it says:
While it’s generally poor practice, you can use Axios directly in your components to fetch data from a method, lifecycle hook, or whenever.
I am wondering why? I usually use lifecycle hooks a lot to fetch data (especially from created()). Where should we write the request calls?
Writing API methods directly in components increases code lines and make difficult to read.
As far as I believe the author is suggesting to separate API methods into a Service.
Let's take a case where you have to fetch top posts and operate on data. If you do that in component it is not re-usable, you have to duplicate it in other components where ever you want to use it.
export default {
data: () => ({
top: [],
errors: []
}),
// Fetches posts when the component is created.
created() {
axios.get(`http://jsonplaceholder.typicode.com/posts/top`)
.then(response => {
// flattening the response
this.top = response.data.map(item => {
title: item.title,
timestamp: item.timestamp,
author: item.author
})
})
.catch(e => {
this.errors.push(e)
})
}
}
So when you need to fetch top post in another component you have to duplicate the code.
Now let's put API methods in a Service.
api.js file
const fetchTopPosts = function() {
return axios.get(`http://jsonplaceholder.typicode.com/posts/top`)
.then(response => {
// flattening the response
this.top = response.data.map(item => {
title: item.title,
timestamp: item.timestamp,
author: item.author
})
}) // you can also make a chain.
}
export default {
fetchTopPosts: fetchTopPosts
}
So you use the above API methods in any components you wish.
After this:
import API from 'path_to_api.js_file'
export default {
data: () => ({
top: [],
errors: []
}),
// Fetches posts when the component is created.
created() {
API.fetchTopPosts().then(top => {
this.top = top
})
.catch(e => {
this.errors.push(e)
})
}
}
It's fine for small apps or widgets, but in a real SPA, it's better to abstract away your API into its own module, and if you use vuex, to use actions to call that api module.
Your component should not be concerned with how and from where its data is coming. The component is responsible for UI, not AJAX.
import api from './api.js'
created() {
api.getUsers().then( users => {
this.users = users
})
}
// vs.
created() {
axios.get('/users').then({ data }=> {
this.users = data
})
}
In the above example, your "axios-free" code is not really much shorter, but imagine what you could potentially keep out of the component:
handling HTTP errors, e.g. retrying
pre-formatting data from the server so it fits your component
header configuration (content-type, access token ...)
creating FormData for POSTing e.g. image files
the list can get long. all of that doesn't belong into the component because it has nothing to do with the view. The view only needs the resulting data or error message.
It also means that you can test your components and api independently.