I'm learning React and practicing how to use 'fetch' in React.
I have successfully fetched some API. I listed some random content out of this API, such as 'Title', 'Author' and 'Points'. However, I noted that some don't have the 'Title'. I don't like those that don't have 'Title'(leaving it blank). I'd like to automatically add 'A/N' in those lists that don't have the 'Title'.
Does anybody can teach me how to do that?
Here is my code:
import React, { Component } from 'react';
import './App.css';
class App extends Component{
constructor(){
super();
this.state={
hits: [],
isLoading: false,
error: null,
}
}
componentDidMount(){
this.setState({
isLoading: true
})
fetch('https://hn.algolia.com/api/v1/search?query=')
.then(response => {
if(response.ok){
return response.json()
}else{
throw new Error('Something went wrong...')
}
})
.then(data => this.setState({
hits: data.hits,
isLoading: false
}))
.catch(error => this.setState({
error: null,
isLoading: false
}))
}
render(){
const {hits, isLoading, error} = this.state;
if(isLoading){
return <p>Loading ... </p>
}
if(error){
return <p>{error.message}</p>
}
return(
<div className="container">
{hits.map(data =>
<ul key={data.objectID}>
<li><a href={data.url}>Title: {data.title}</a></li>
<li>Author:{data.author}</li>
<li>Points: {data.points}</li>
</ul>
)}
</div>
)
}
}
export default App
You can make use of !! operator to achieve this
Here is you code
import React, { Component } from 'react';
import './App.css';
class App extends Component{
constructor(){
super();
this.state={
hits: [],
isLoading: false,
error: null,
}
}
componentDidMount(){
this.setState({
isLoading: true
})
fetch('https://hn.algolia.com/api/v1/search?query=')
.then(response => {
if(response.ok){
return response.json()
}else{
throw new Error('Something went wrong...')
}
})
.then(data => this.setState({
hits: data.hits,
isLoading: false
}))
.catch(error => this.setState({
error: null,
isLoading: false
}))
}
render(){
const {hits, isLoading, error} = this.state;
if(isLoading){
return <p>Loading ... </p>
}
if(error){
return <p>{error.message}</p>
}
return(
<div className="container">
{hits.map(data =>
<ul key={data.objectID}>
<li><a href={data.url}>Title: {!!data.title ? data.title : "A/N" }</a></li>
<li>Author:{data.author}</li>
<li>Points: {data.points}</li>
</ul>
)}
</div>
)
}
}
export default App
ALternative way to achieve this
Set const default_title to 'n/a'; and use in render function.
You can use map() and save data like this:
fetch('https://hn.algolia.com/api/v1/search?query=')
.then(response => {
if(response.ok){
return response.json()
}else{
throw new Error('Something went wrong...')
}
})
.then(data => this.setState({
hits: data.hits.map( item => {
if(!item.Title){
item.Title = 'A/N';
}
return item;
}),
isLoading: false
}))
.catch(error => this.setState({
error: null,
isLoading: false
}))
Related
i can discord oauth2 typescript & react But I am confronted with this error. I don't know how to solve it. Could you please help?
It constantly renews me at the address I entered, please help me about this topic.
import React, { Component } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom"
import fetch from "node-fetch";
import NavigationBar from "./navigation/NavigationBar";
import ServerSelection from "../pages/ServerSelection";
export default class App extends Component {
state = {
loading: true,
user: null
}
componentDidMount() {
fetch("http://192.168.1.34:8080/oauth/details", {
credentials: "include"
})
.then(res => res.json())
.then(res => {
if (!res) return this.setState({ loading: false });
this.setState({
loading: false,
user: res
})
})
.catch(() => this.setState({ loading: false }));
}
render() {
if (this.state.loading) {
return (
<React.Fragment>
<div className="container">
<h1>Loading...</h1>
</div>
</React.Fragment>
);
} else if (!this.state.user) {
window.location.replace("http://192.168.1.34:8080/oauth/login");
The error is caused by your render() method not returning any component.
You have an if and else-if blocks in your render method, but what if both conditions fail? you render() method should have a final return statement or an else block.
The error is caused by this line:
.catch(() => this.setState({ loading: false }));
So when your fetch encounters and error, it sets loading to false, then when your compoenent tries to render, this happens:
if (this.state.loading)
loading is false so that condition fails
this.setState({
loading: false,//loading was set to false
user: res
})
this condition also fails because you have assigned a value to the state.user
.then(res => {
if (!res) return this.setState({ loading: false });
this.setState({
loading: false,
user: res//user is also not falsey
})
The solution is to add a final return statement:
render() {
if (this.state.loading) {
return (
<React.Fragment>
<div className="container">
<h1>Loading...</h1>
</div>
</React.Fragment>
);
} else if (!this.state.user) {
window.location.replace("http://192.168.1.34:8080/oauth/login");
return <p>EMPTY USER</p>;
}
return <p>CONDITIONS FAILED</p>;
}
I am new at react and
I have been trying to apply event handling in react but facing some Problem on onclick event.
When the button "show me of germany" is called the Page then stuck to loading only ...
Here is the code i have written ..
class App extends Component {
constructor(props) {
super(props);
this.state = { articles: [],
isLoaded:false ,
country:'us'
}
this.change = this.change.bind(this);
}
componentDidMount() {
const APIurl = `https://newsapi.org/v2/top-headlines?country=${this.state.country}&apiKey=${API_KEY}`;
fetch(APIurl)
.then(response => response.json())
.then(json => {
this.setState({
articles: json.articles,
isLoaded:true
})
})
}
// function to change the state
change()
{
this.setState({
articles: [],
isLoaded:false ,
country:"de"
})
}
render() {
const { isLoaded,articles } = this.state;
if(!isLoaded)
{
return (<h1>Loading....</h1>)
}
return (
<div>
<Navbar/>
<button onClick={this.change}>show me of germany</button>
<ul>
{articles.map(item=>(
<News item={item}/>
))}
</ul>
</div>
);
}
}
export default App;
Hope you understood the problem
You have to do request again.
class App extends Component {
constructor(props) {
super(props);
this.state = {
articles: [],
isLoaded: false,
country:'us'
}
this.change = this.change.bind(this);
}
componentDidMount() {
fetchData(this.state.country);
}
componentDidUpdate(prevProps, prevState) {
const { country: prevCountry } = prevState;
const { country: nextCountry } = this.state;
if (prevCountry !== nextCountry) {
fetchData(nextCountry);
}
}
change() {
this.setState({ country: 'de' });
}
fetchData(country) {
this.setState({ articles: [], isLoaded: false });
fetch(
`https://newsapi.org/v2/top-headlines?country=${country}&apiKey=${API_KEY}`
)
.then(res => res.json())
.then(({ articles }) => {
this.setState({ articles, isLoaded: true });
})
.catch(console.error);
}
render() {
//...
}
}
export default App;
I'm trying to do a basic API fetch and show that information onClick using a button called GENERATE. All it should do for now is show the first url in the json I receive.
Once that is achieved, I want it to show the next url on each click.
App.js
import React, { Component } from 'react';
import { ThemeProvider, createToolkitTheme } from 'internaltools/theme';
import { AppHeader } from 'internaltools/app-header';
const LIGHT_THEME = createToolkitTheme('light');
const DARK_THEME = createToolkitTheme('dark');
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
componentDidMount(){
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong with the API...');
}
})
.then(data => this.setState({ hits: data.hits[0], isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
const { hits, isLoading, error } = this.state;
return (
<>
<button onClick={hits.url}>GENERATE</button>
</>
);
}
}
Please help me find out why my button doesn't work. And how do I iterate over the urls on each click, i.e. show the next url from the json on each click. Thanks.
You should pass a function name to your onClick handler. Then in that function you can access the data you wanted.
enter code here
import React, { Component } from 'react';
import { ThemeProvider, createToolkitTheme } from 'internaltools/theme';
import { AppHeader } from 'internaltools/app-header';
const LIGHT_THEME = createToolkitTheme('light');
const DARK_THEME = createToolkitTheme('dark');
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
hitsCount: 0
};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount(){
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong with the API...');
}
})
.then(data =>
this.setState({ hits: data.hits, hitsCount: 0 ,isLoading: false
}))
.catch(error => this.setState({ error, isLoading: false }));
}
handleClick(){
this.setState(prevState => ({ hitsCount: prevState.hitsCount + 1
}));
}
render() {
const { hits, hitsCount, isLoading, error } = this.state;
return (
<>
<div>
count: {hitsCount}
url: {hits[hitsCount].url}
</div>
<button onClick={this.handleClick}>GENERATE</button>
</>
);
}
}
You need to pass an onClick handler function to update a state value.
Here's a codesandbox that stores the hits array in state along with a current index, and a handler that simply increments the index.
Consider This:
Read through the comments in the code to get the updates.
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
currentHit: 0, //add a state currentHit to hold the url that is displayed by now
isLoading: false,
error: null,
};
}
componentDidMount(){
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong with the API...');
}
})
.then(data => this.setState({ hits: data.hits, isLoading: false })) //Make hits array holding all the hits in the response instead of only the first one
.catch(error => this.setState({ error, isLoading: false }));
}
handleClick = () => {
this.setState(prevState => ({
currentHit: prevState.currentHit + 1,
}));
}
render() {
const { hits, isLoading, error, currentHit } = this.state;
// pass the handleClick function as a callback for onClick event in the button.
return (
<>
<p>{hits[currentHit].url}<p/>
<button onClick={this.handleClick.bind(this)}>GENERATE</button>
</>
);
}
}
Here is the working code, on each click next url will be shown.
codesandbox link
handleChange method can work if you want to append the url from array as well. Or you could just increment the index in this function.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
state = {
data: [],
index: 0
};
componentDidMount() {
this.setState({ isLoading: true });
fetch("https://reqres.in/api/users")
.then(response => {
if (response) {
return response.json();
} else {
throw new Error("Something went wrong with the API...");
}
})
.then(data => this.setState({ data: data.data }))
.catch(error => this.setState({ error }));
}
handleChange = () => {
let i =
this.state.index < this.state.data.length ? (this.state.index += 1) : 0;
this.setState({ index: i });
};
render() {
return (
<div className="App">
<span>
{this.state.data.length && this.state.data[this.state.index].avatar}
</span>
<button onClick={this.handleChange}>GENERATE</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
So I want to call an API with react and my data is not showing up correctly I know I did it right but is there anything I am missing because I don't know why it is still showing Loading
import React from 'react';
import './App.css';
class App extends React.Component {
constructor (props) {
super(props);
this.state = {
students: [],
isLoaded: false,
error: null,
}
}
componentDidMount() {
fetch("http://localhost:3200/students")
.then(res => res.json())
.then((myresult) => {
this.setState({
isLoaded: true,
students: myresult.students,
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const {error, isLoaded, students} = this.state;
if (error) {
return <div>Error: {error.message}</div>
} else if (isLoaded) {
return <div> Loading ...</div>
} else {
return (
<ul>
{students && students.map(student => (
<li key={student._id}>
{student._id} {student.role_num}
</li>
))}
</ul>
);
}
}
}
export default App;
I am trying to display information from this URL http://localhost:3200/students
I was following this link on how to call an API https://reactjs.org/docs/faq-ajax.html
hey guys updated my code I am still getting the same issue stuck on loading I don't know whether I am passing in my data properly
I think there a couple of things going on here but main points are
its componentDidMount not MountComponent
your not setting students correctly in state
In you code above for MountComponent see that you are setting up movieItems and your state is expecting students. To solve the issue use the code below.
MountComponent = () => {
fetch("http://localhost:3200/students")
.then(res => res.json())
.then((myresult) => {
this.setState({
isLoaded: true,
students: myresult.students,
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
change this:
} else if (!isLoaded) {
to:
} else if (isLoaded) {
Write this in your function and check
componentDidMount() {
fetch("http://localhost:3200/students").then(res => {
this.setState({ students : res.data })
})
}
I am trying to fetch the message outputted by the following endpoint:
http://helloworld-env-2.5fwknpgms8.us-east-2.elasticbeanstalk.com/
I just ran a create-react-app to create my application and changed the code in the App.js file
New Code:
import React, { Component } from 'react';
import './App.css';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
error: null,
isLoaded: false,
items: ""
};
}
componentDidMount(){
console.log("mounting component");
fetch("http://helloworld-env-2.5fwknpgms8.us-east-2.elasticbeanstalk.com/")
.then((result) => {
this.setState({
isLoaded: true,
items: result
});
});
}
render() {
console.log("rendering");
const isLoaded = this.state.isLoaded;
if(isLoaded){
return (<div> {this.state.items} </div>);
}
else{
return (
<div>loading</div>
);
}
}
}
export default App;
I keep getting the loading message.
You need to parse the response from fetch:
componentDidMount(){
fetch("http://helloworld-env-2.5fwknpgms8.us-east-2.elasticbeanstalk.com/")
.then((result) => result.json()) // here
.then((result) => {
const { a } = result; // access 'a' key from response
this.setState({
isLoaded: true,
items: a
});
});
}
Here are the docs.