Get All The youtube video from specific channel in reactjs - reactjs

I am trying to get video from a specific channel in youtube using youtube data api using reactjs.But my api query doesnot return anything.Here is what i've tried for getting the video.What am i doing wrong here.
componentDidMount() {
console.log('componentDidMount colling ...');
fetch('https://www.googleapis.com/youtube/v3/channels?key="MYAPIKEY"&channelId="MYCHANNELID"&part=snippet,id&order=date&maxResults=2')
.then(results => {
this.setState({videos: results.json()});
this.setState({playingVideoId: this.state.videos[this.index]});
console.log("videos",this.state.videos)
console.log("videos",this.state.playingVideoId)
})
}

First try to use postman to see if URL is returning correct data.
Second: setState is asynchronous which means, if you console.log right after setting state, you won't get correct results. Also, your second call to setState is using data from first call therefore you won't get right results. Just call setState once and use callback to log what you got.
componentDidMount() {
console.log('componentDidMount colling ...');
fetch('https://www.googleapis.com/youtube/v3/channels?key="MYAPIKEY"&channelId="MYCHANNELID"&part=snippet,id&order=date&maxResults=2')
.then(results => {
const videosObj = results.json();
this.setState({
videos: videosObj,
playingVideoId: videosObj[this.index]
}, (updatedState) => {
console.log("videos", updatedState.videos);
console.log("videos", updatedState.playingVideoId);
});
})
}

Related

React: Can't figure out how to use fetched API response

I'm working with a nice chatbot program for React someone wrote, and the thing is, you can actually bind the bot's responses to function calls like this:
render() {
const { classes } = this.props;
return (
<ChatBot
steps={[
{
...
{
id: '3',
message: ({ previousValue, steps }) => {
this.askAnswer(previousValue)
},
end: true,
},
]}
/>
);
Where message is the answer of the bot that it calculates based on the previousValue and askAnswer is a custom function you'd write. I'm using an API that inputs the previousValue to a GPT model, and I want to print the response of this API.
However, I just can't wrap my head around how I could pass the response of the API to the message. I'm trying this:
constructor(props) {
super(props);
this.state = { response: " " };
}
...
askAnswer(question) {
var jsonData = { "lastConversations": [question] }
fetch('http://my_ip:80/query', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(jsonData)
}).then(response => response.json())
.then(data => { this.setState({ response: data["botResponse"] }) });
return (this.state.response)
}
I've been struggling with this for the past 2-3 hours now.
I've tried a couple of combinations, and nothing seems to work:
If I do as seen above, it seems like this.state.response just won't get
updated (logging data["botResponse"] shows there is a correct
reply, so the API part works and I get the correct response).
If I try async-await for askAnswer and the fetch call, then I can
only return a Promise, which is then incompatible as input for the
ChatBot message.
If I do not await for the fetch to complete, then
this.state.response just stays the default " ".
If I return the correct data["botResponse"] from within the second .then after the fetch, nothing happens.
How am I supposed to get the API result JSON's data["botResponse"] text field out of the fetch scope so that I can pass it to message as a text? Or, how can I get a non-Promise string return after an await (AFAIK this is not possible)?
Thank you!
In your last 2 line
.then(data => { this.setState({ response: data["botResponse"] }) });
return (this.state.response)
You are updating the state and trying to read and return the value in the same function which I think will never work due to async behaviour of state. (this is why your this.state.response in the return statement is the previous value, not the updated state value).
I'm not sure but you can write a callback on this.setState and return from there, the callback will read the updated state value and you can return the new state.

React Native get dynamic data

there is a data which is changing every second in my api and i should get it dynamically to react native screen and im using setInterval
I writed a function which is send request and get data every second and i should refresh this function and i did use setInterval but im not sure about that is this healthy? also i could not solve this because i got an error that :
Possible Unhandled Promise Rejection (id: 7):
TypeError: _this2.setState is not a function. (In '_this2.setState({
kalanzaman: res.data
})', '_this2.setState' is undefined)
My func and how am i calling it :
dynamically() {
// console.log("bom")
axios.get(`http://localhost:5000/kalanzaman`)
.then(res => {
this.setState({ kalanzaman: res.data })
})
}
.
setInterval(this.dynamically, 1000)
Which way should i use for get dynamic data to react native from my api?
Instead of Http request, you can use Websocket.
It is a two-way interactive communication session between the user's browser and a server.
for example: have a look at Socket.IO
Maybe it would be better if you write it like this:
setInterval(() => {
dynamically() {
// console.log("bom")
axios.get(`http://localhost:5000/kalanzaman`)
.then(res => {
this.setState({ kalanzaman: res.data })
}).catch((error) => {
alert('Something Error')
})
}
}, 100);
You must cath() for catching the error, and put it on componentDidMount

async/await is not working with react.js inside ComponentDidMount

I'm trying to fetch data using axios.
This code is working:
componentDidMount(){
const posts = axios.get("https://jsonplaceholder.typicode.com/posts");
console.log(posts);
}
but this doesn't:
async componentDidMount(){
const data = await axios.get("https://jsonplaceholder.typicode.com/posts");
console.log(data)
}
Any idea why it's not working?
There is nothig special in componentDidMount that could prevent it from being async. This particular issue looks like an Axios issue. It's pretty easy to check using fetch:
async componentDidMount() {
const data = await fetch("https://jsonplaceholder.typicode.com/posts");
console.log(await data.json())
}
It is not quite clear what you are referring to when saying "this code works":
The output in the console will not be your lists of posts, right?
But you don't need to use async/await, they are just syntactic sugar.
The value synchronously returned by the call to axios.get is a Promise so you can also use then and catch:
componentDidMount(){
axios.get("https://jsonplaceholder.typicode.com/posts")
.then(console.log)
.catch(console.error);
}
This way you you don't need async/await support in react which seems to be non trivial to set up correctly as this article states: https://www.valentinog.com/blog/await-react/
be aware that the component will render anyway since it not aware that you are still waiting for the data to load. So when the data loads and you updated your state it will need to render again.
Your both the snippets are working fine.
Your code,
componentDidMount(){
const posts = axios.get("https://jsonplaceholder.typicode.com/posts");
console.log(posts);
}
Here console.log(posts) will return only Promise and not actual data.
And using async/await,
async componentDidMount(){
const posts = await axios.get("https://jsonplaceholder.typicode.com/posts");
console.log(posts);
console.log(posts.data);
console.log(JSON.stringify(posts.data))
console.log(JSON.stringify(posts.data[0]));
}
Here also,
console.log(posts) - Will return Promise object and not actual data
console.log(posts.data) - This will return actual data array
console.log(JSON.stringify(posts.data)) - This will return stringified version of actual data
console.log(JSON.stringify(posts.data[0])) - This will return stringified version of first record in actual data.
Demo

How to handle the case where the axios response comes after the component is rendered?

I am creating a blog application in rest framework and reactjs. On the home page, under componentDidMount, I send an API call using axios to get all the articles and setState of articles to the return. As I have studied, axios works on the idea of promise such that the code doesnt proceed, if the API is not fetched for a particular component. Please tell me, if I am wrong.
Then, I send a GET call to get the writer's name, who wrote the article by the id. Though, I assumed that the axios works as a promise. But, it doesnt work that way. Now, I am not sure how to move ahead.
Here is a snippet. So, in mainBody.js, I make the api call as:
class MainBody extends Component {
state = {};
componentDidMount () {
this.get_all_articles();
};
get_writer_name (id) {
let authstr = 'Bearer ' + window.localStorage.token;
let writer_url = "http://localhost:8000/api/writer/" + id.toString() + "/";
axios.get(writer_url, { headers: { Authorization: authstr }})
.then(response => {
console.log(response.data['name'])
return response.data['name'];
})
.catch(err => {
console.log("Got error")
})
};
get_all_articles () {
let authstr = 'Bearer ' + window.localStorage.token;
axios.get("http://localhost:8000/api/articles/", { headers: { Authorization: authstr }})
.then(response => {
this.setState({articles: response.data});
})
.catch(err => {
console.log("Got error")
})
}
render () {
return (
{this.state.articles.map((article, key) =>
<ArticleView key={article.id} article={article} writer_name={this.get_writer_name(article.created_by)} />
)}
)
}
}
In articleview2, I print all the data that is present in each of the articles along with the writer's name.
My articleview class is:
class ArticleView extends Component {
state = {article: this.props.article};
componentDidMount() {
console.log(this.props.writer_name;
}
render () {
return (
<React.Fragment>
<h2>{article.title}</h2>
<p>{article.body}</p>
<span>{this.props.writer_name}</span>
</React.Fragment>
)
}
}
If you see closely, I wrote two console.log statements to get the writer names. Based on the order, first the console log present in articleview class runs, which is undefined, and thenafter the data is fetched from the API call and the console log runs which returns the correct writer name.
I wanted to know, where is the error? Also, as I noticed, there are too many API calls being made to get the writer's name multiple time for all the listed articles. What are the industry best practices for these cases?
I want to know where is the error.
When you are writing this.state.articles.map(), means you're using property map of the Array articles which may be undefined before the data is fetched that will cause you the error Cannot read property map of undefined.
Solution
Now, as the API request is asynchronous, means render method will not wait for the data to come. So what you can do is use a loader variable in the state, and set it to true as long as the request is being made, and when the response has come, make it false, and show the loader in render when this.state.loader is true, and show articles when it is false.
Or you can initialize this.state.articles with an empty array that won't cause you the error.
Also, as I noticed, there are too many API calls being made to get the writer's name multiple time for all the listed articles. What are the industry best practices for these cases?
It is extremely bad practice to make an API request in the loop. Even myself has been scolded on it once I did it in my company.
Solution
You have tell your backend engineer to provide you filter for including the writer's name in each object of the article. We use Loopback on our backend, which provides a filter for including the related model in each object internally.
Since your API calls have a lot of things in common, you should first set up an axios instance that re-uses those common features:
const api = axios.create({
baseURL: 'http://localhost:8000/api/',
headers: { Authorization: `Bearer ${localStorage.token}` }
});
Now since your MainBody needs to fetch the resources from the API asynchronously, there will be a short period where the data is not yet available. There are two ways you can handle this. Either the MainBody can be responsible for making all the calls, or it can be responsible for just making the call to get all the articles, then each of the ArticleView components can be responsible for getting the writer's name. I'll demonstrate the first approach below:
class MainBody extends Component {
state = { articles: null, error: null, isLoading: true };
async componentDidMount () {
try {
const response = await api.get('articles/');
const articles = await Promise.all(
response.data.map(async article => {
const response = await api.get(`writer/${article.created_by}/`);
return { ...article, writer_name: response.data.name };
})
);
this.setState({ articles, isLoading: false });
} catch (error) {
this.setState({ error, isLoading: false });
}
}
render () {
const { articles, error, isLoading } = this.state;
return isLoading ? 'Loading...' : error
? `Error ${error.message}`
: articles.map(article => (
<ArticleView
key={article.id}
article={article}
writer_name={article.writer_name}
/>
)
);
}
}

cannot access an array of objects returned from api call in react

I have an API call, that is called multiple times inside a map function to retrieve nested data from mongodb.
The results are pushed to an array.
The array is used as props data for a child component.
I can console.log() the resulting array. but I cannot access it in react, or iterate through it.
Does anyone know how to sort this problem. It should work. I can't see any reason for it not to. It's becoming very frustrating
fetchMemory(props) {
const tempMemories = [];
if (props.journey) {
props.journey.memories.map((mem) = > {
superagent
.get(`/memories/$ {
mem
}`)
.end(function (err, res) {
let tp = res.body
tempMemories.push(tp)
});
})
this.setState({
memories: tempMemories
})
}
}
I cannot access the array of memories returned in setstate. they do show up if you inspect them in the console/ It just returns an error, in the child component (as props).
"TypeError: Cannot read property 'memories' of undefined"
Thanks in advance.
Fetch data via axios is async, so basically tempMemories will be empty in your call to setState(), because the network calls aren't completed yet.
You should use Promise.all like this:
const promiseList = props.journey.memories.map( mem => {
return superagent
.get(`/memories/${mem}`)
.then( res => res.body );
});
Promise.all( promiseList )
.then( results => {
this.setState({
memories: results
});
})
.catch( err => {
...
});
So basically you create one promise for each element and then wait for all of them to get resolved to do the setState() call.

Resources