I'm trying myself in react and trying to make a simple application, which will display articles from the Hacker News. I have already made the first call to their API
componentDidMount() {
fetch('https://hacker-news.firebaseio.com/v0/jobstories.json?print=pretty')
.then(res => res.json())
.then(articles => {
this.setState({articles})
})
}
As the response, it returns an array of the articles IDs. To get detailed information for every single article I need to iterate the array I get and to make a second request for every article ID which has to look like
fetch(`https://hacker-news.firebaseio.com/v0/item/{id_from_the_array}`)
And I faced the problem because I have no idea how to implement it in a correct way.. Could someone please advice me?
this will help you
import React from "react";
import { render } from "react-dom";
import Hello from "./Hello";
class App extends React.Component {
state = {
articles: []
};
componentDidMount() {
fetch("https://hacker-news.firebaseio.com/v0/jobstories.json?print=pretty")
.then(res => res.json())
.then(articles => {
articles.map(item => {
fetch(`https://hacker-news.firebaseio.com/v0/item/${item}.json?print=pretty`)
.then(res => res.json())
.then(detailArticles => {
const articles = this.state.articles.concat(detailArticles);
this.setState({ articles });
});
});
});
}
render() {
return <p>{JSON.stringify(this.state.articles) }</p>;
}
}
render(<App />, document.getElementById("root"));
codesandbox
One way you can do is like using pagenation or infinite scroll so you can show some 10 or 15 news on the screen and load the next set of data on click of a button. Else you can show only id's on screen and fetch the data on click of a button.
Related
I'm creating a blog, using React.
I uploaded some parts: https://codesandbox.io/s/youthful-bush-z3cce
There is one note on the main page and a list of other notes. When I click on some link of these notes, it opens and I can see another post. But if I try to click again on another post, it doesn't reload, though it changes the url.
It's because you have the same component rendering your posts. Your componentDidMount runs only once and it is responsible for calling your api. You need to get the api logic in a different function and call it again in componentDidUpdate.
I have done it in a codesanbox repo - https://codesandbox.io/s/musing-grass-sxokl
componentDidMount() {
if (!this.props.match) {
return;
} else {
this.callApi();
}
}
componentDidUpdate() {
this.callApi();
}
callApi = () => {
client
.getEntries({
content_type: "blogPost",
"fields.slug": this.props.match.params.slug
})
.then(response => {
console.log(response);
this.setState(
{
content: response.items[0].fields.content,
title: response.items[0].fields.title,
date: response.items[0].fields.date,
country: response.items[0].fields.country
},
() => console.log(this.state)
);
});
};
Hope this helps you.
I am trying to get SWAPI data from 'people' using react. I would ultimately like to retrieve the data and then set the people and create a card from the 10 people on page 1. When I console.log my response I am able to see the object returned. I am trying to set that using response.data.results (should contain people).
//full code:
import React, { useState, useEffect } from 'react';
import axios from "axios";
import Cards from "./components/Card"
function People() {
const [people, setPeople] = useState([]);
useEffect(() => {
axios.get('https://swapi.co/api/people/')
.then(res => {
//console.log(res);
setPeople(res.data.results)
})
.catch(err => {
console.log(`Data not received ${err}`)
})
}, [])
return (
<div className = "container">
{people.map((name, index) => {
return <Cards name={name} index={index}/>
})}
</div>
)
}
export default People;
When I console.log swPeople after using setswPeople I am returned an empty array.
Any ideas as to why the set is not giving me an array containing the 10 people on page one?
I see it working https://codesandbox.io/s/react-hooks-useeffect-frhmn
it take time to set the state , if we dont pass the second argument [] to useEffect you will see it is returning data correctly but that will cause the infinite loop , so we avoid that
import React, { useState, useEffect } from 'react';
import axios from "axios";
import Cards from "./components/Card"
function People() {
const [people, setPeople] = useState([]);
useEffect(() => {
axios.get('https://swapi.co/api/people/')
.then(res => {
//console.log(res);
setPeople(res.data.results)
})
.catch(err => {
console.log(`Data not received ${err}`)
})
}, [])
return (
<div className = "container">
{people.map((name, index) => {
return <Cards name={name} index={index}/>
})}
</div>
)
}
looks like this worked after all but it was taking close to 30s for me to see that info logged in console and I was being impatient
Have you tried to enter this url in your browser, https://swapi.co/api/people?
Because it seems the link is redirecting to another url while it needs to brign you back a JSON.
If you want to use SWAPI info replace you SWAPI to https://www.swapi.tech/api/people
it works well.
However I suggeust you to download the extension of JSONVue it will help you track your data with comfortable JSON view in your broweser.
And about the info of the 10 people you trying to get from SWAPI, when you'll open the browser with the new SWAPI adress, try to track the path you want to do in your code. You'll see the info you're trying to catch is leading to another API.
Is there anyway or example to make fetch and show data directly.
Say we have JSON data and we want to show once some data available so if there many objects in the JSON and once one data object is ready we show it and wait until next once and load once ready as well. We do this all in one endpoint.
Regards
What your describing is pretty standard in React.
Say you have your List component, and when the component mounts you watch to make a fetch to your API and render the data. You could do something like the below.
import React, {Component} from 'react'
export default class List extends Component {
state = {
listData: []
}
componentDidMount = () =>{
fetch('YOUR_URL_HERE')
.then(response => response.json())
.then(data => this.setState({ listData: data}));
}
render(){
return(
<div>
{this.state.listData.map((listItem, i)=>{
return <p>{listItem.propertyToRender}</p>
})}
</div>
)
}
}
I am currently working on pushing to a log in page on the confirmation of a user via email. Problem is, I would like to first re-direct the user confirming to a page thanking them for registering and a few seconds later push to the log in page. What's the best way of approaching this?
I have a push to the log in page that is happening right away, would like to delay it a few seconds.
confirmSuccess = () => {
this.setState(() => ({ success: true }));
this.props.history.push("/login", { fromRegistration: true });
};
Currently as soon as the user clicks on "confirm account" it pushes them straight the log in page, would like to have it delayed so the "thank you for registering" page can appear first.
You can create a new component like this
import React from "react"
import { withRouter } from "react-router-dom"
class ThankYouComponent extends React.Component {
componentDidMount() {
setTimeout(() => {this.props.history.push("/login")}, 5000) // redirect in 5 secs
}
render() {
return(
<h1>Thank You</h1>
)
}
}
export default withRouter(ThankYouComponent)
and in your confirmSuccess function redirect to ThankYouComponent page instead:
confirmSuccess = () => {
this.setState(() => ({ success: true }));
this.props.history.push("/thankYouPage", { fromRegistration: true });
};
And of course don't forget to add ThankYouComponent to Routes
I am new to rxjs Observables. I am trying simple login page application. When I am sending correct credentials, code is working fine and loading spinner also stops rendering. When credentials are invalid then code stops working and spinner also stays on the page. I have to reload the page to make it work again.
Here's the code :
import constants from "../constants";
import "rxjs";
import { ajax } from "rxjs/observable/dom/ajax";
import { loginBody } from "../utils/bodyCreator";
import {
showLoadingSpinner,
hideLoadingSpinner
} from "../actions/LoadingOverlayActions";
const sessionCreated = payload => ({
type: constants.sessionCreated,
response: payload
});
export const tryLoginEpic = (action$, store) =>
action$
.ofType(constants.tryLogin)
.map(() => store.dispatch(showLoadingSpinner()))
.mergeMap(action =>
ajax
.post(constants.loginEndPoint, loginBody(store.getState()), {
"Content-Type": "application/json"
})
.map(data => store.dispatch(sessionCreated(data.response)))
.map(() => store.dispatch(hideLoadingSpinner()))
.catch(err => store.dispatch(hideLoadingSpinner()))
);
Please help me how to do this and what is wrong in this code?
Thanks
You need to use .catch operator in a different way. For example, return empty Observable (or other action), something like:
.catch(error => {
store.dispatch(hideLoadingSpinner());
return Observable.empty();
})
see official documentation on catchError operator