axios get function not working in Reactjs - javascript

I am working on a web dev using ReactJs, NodeJs and Mysql. I got problem in displaying fetching data using axios.
here is my API :
app.get('/enduser',(req, res) => {
let ENDUSER_QUERY = "SELECT * FROM enduser_tbl";
let query = dbConn.query(ENDUSER_QUERY, (err, results) => {
if(err) {
console.log(err)
} else {
return res.status(200).json({"status": 200, "err" : null, "response": results});
}
});
});
and I call the API in my reactjs page component
class ProjectList extends Component {
constructor(props){
super(props);
this.state = {
enduser_tbl : []
}
}
async componentDidMount() {
const Url = "http://localhost:4000/enduser"
await axios.get(Url)
.then( enduser_tbl => {
console.log(enduser_tbl.data)
this.setState({
enduser_tbl : enduser_tbl.data
})
})
}
render() {
const enduser_tbl = this.state;
return (
<Container>
{ enduser_tbl.map ((enduser, project_id) =>
<ListGroup>
<ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
</ListGroup>
)}
</Container>
)
}
}
export default ProjectList
I got no error in my terminal but many problem appears in Chrome. here is the response from chrome

Error in destructuring, missed curly brace const { enduser_tbl }
render() {
const { enduser_tbl = [] } = this.state;
return (
<Container>
{ enduser_tbl.map ((enduser, project_id) =>
<ListGroup>
<ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
</ListGroup>
)}
</Container>
)
}
For safe side:
const Url = "http://localhost:4000/enduser"
await axios.get(Url)
.then( { data: enduser_tbl = [] } => {
console.log(data)
this.setState({
enduser_tbl
})
})

enduser_tbl.data will be undefined,
it will be either enduser_tbl.response or enduser_tbl which you are setting in your state.
this.setState({
enduser_tbl : enduser_tbl.response
})

Two things, you are not getting the correct piece of the state in your render function. You also need to deal with that both the API call and setState are async, so you can't rely on it being defined when your component is rendered.
You can do it like this:
const enduser_tbl = this.state.enduser_tbl || [];
return (
<Container>
{ enduser_tbl.map ((enduser, project_id) =>
<ListGroup>
<ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
</ListGroup>
)}
</Container>
)

I think that you are trying to map an object because this.state is an object. Try changing the code as given below.
class ProjectList extends Component {
constructor(props){
super(props);
this.state = {
enduser_tbl : []
}
}
async componentDidMount() {
const Url = "http://localhost:4000/enduser"
await axios.get(Url)
.then( enduser_tbl => {
console.log(enduser_tbl.data)
this.setState({
enduser_tbl : enduser_tbl.data
})
})
}
render() {
const enduser_tbl = this.state.enduser_tbl;
return (
<Container>
{ enduser_tbl.map ((enduser, project_id) =>
<ListGroup>
<ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
</ListGroup>
)}
</Container>
)
}
}

This error rises because you are not passing array to map function please add below code and let me know is it work for you are not
componentDidMount = async (e) =>{
const url = "http://localhost:4000/enduser"
try{
const res = await axios.get(url)
this.setState({
enduser_tbl :res.data
})
}
ctach(ex){
console.log(ex)
}
}

First, check your API response it might look like this
{
"status": 200,
"response": [{...}, {...}]
}
then when receiving your data make sure you've set it to the state properly
e.g:
await axios.get(Url)
.then(enduser_tbl => {
this.setState({
enduser_tbl: enduser_tbl.response
})
})
finally, make sure that you've destructured it properly just like xdeepkav said e.g
const { enduser_tbl } = this.state;
The error the you're encountering is because enduser_tbl can't be read as mappable data/array. To make it clear here's an example of your error

Related

Looping through an object in react

Learning react
Trying to loop through an object from an API call that returns a json object and display it but struggling to implement it
This is the component that should render it
export default class ProfilePage extends Component {
constructor() {
super();
this.state = { data: '' };
}
mapObject(object, callback) {
return Object.keys(object).map(function (key) {
return callback(key, object[key]);
})
}
async componentDidMount() {
const response = await fetch(`https://indapi.kumba.io/webdev/assignment`);
const json = await response.json();
// console.log(json)
this.setState({ data: json });
}
render() {
const data = this.state.data
console.log(data)
return (
<div className="row">
{Object.values(data).map(data => {
<div key={key}>
{data[key]}
</div>
})
}
Woerkkk please
</div>
);
}
}
All I'm getting is a blank screen.
in the console i get the error 'key' is not defined no-undef
You are missing a return statement in your map for your render method.
Edit: Key is not returned from Object.values
Either reconfigure with a return statement like so:
{Object.keys(data).map(key => {
return (<div key={key}>
{data[key]}
</div>);
})
Or alternatively you can implicitly return from arrow function using brackets
{Object.keys(data).map(key => (
<div key={key}>
{data[key]}
</div>)
))
Using Object.values(myObj) you can get all object values as a array. So, with this array, you can iterate over the array and show your items, like this:
{Object.values(myObj).map(value => <p>{value}</p>)}
Don't forget use key prop when iterating.
You can use useState and useEffect to fetch the object data
const App = () => {
const [objData, setObjData] = useState({});
const [objItems, setObjItems] = useState([]);
const fetchObj = async () => {
const response = await fetch(`https://indapi.kumba.io/webdev/assignment`);
const data = await response.json();
setObjData(data);
setObjItems(data.items);
}
useEffect(() => {
fetchObj()
},[]);
return(
<div>
<h1> Order Id :{objData.order_id}</h1>
// or any other objData keys
<h1>Items : </h1>
<ul>
{
objItems.map((i, idx) => {
return(
<li key={idx}>Name : {i.name} , Category: {i.category}, Price: {i.price}, Currency: {i.currency}</li>
)
})
}
</ul>
</div>
)
}
export default App;

How to fix TypeError: (0, _fetchNews.getHomeNews) is not a function in React Native?

I'm building a news reader app using React Native. However when I try to fetch the feed from a url it shows this error:
I'm running the latest version of React Native and Nodejs.
This shows when i run run-android:
This is my News.js:
class News extends Component {
state = {
articles: [],
refreshing: true
};
componentDidMount = () => {
this.fetchNews();
};
fetchNews = () => {
getHomeNews()
.then(articles => {
this.setState({ articles, refreshing: false });
})
.catch(() => this.setState({ refreshing: false }));
};
handleRefresh = () => {
this.setState({ refreshing: true }, () => this.fetchNews());
};
render() {
console.log(this.state.articles);
return (
<FlatList
data={this.state.articles}
renderItem={({ item }) => <Article article={item} />}
keyExtractor={item => item.url}
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh}
/>
);
}
}
And this is my fetchNews.js:
const url = ` URL here`;
export async function getHomeNews() {
let result = await fetch(url).then(response => response.json());
return result.articles;
}
Can anyone show me where I messed up? Thank you for your time.

Re render React Native Flatlist on data fetch from API

I am working on a React Native app where i'm using Flatlist.I have a list to render.But i want to add items to the list which i'm getting from the API on button click. I can see my API data on the console but they are not rendering for some reason. Also the list page i'm talking about is a child component. Here's what it looks like:
class ProductList extends Component {
state = {
isSpinner: false,
newArr: []
};
onScrollEndDrag = async() => {
this.setState({ isSpinner: true });
return await fetch(
`myAPI`
)
.then(response => response.json())
.then(json => {
this.setState({ newArr: [...this.state.newArr, ...(json || [])] })
return json;
})
.catch(error => console.log(error));
}
this.setState({ isSpinner: false });
}
render(){
const list = [data1,data2,data3];
return(
<Fragment>
<FlatList
key={this.key}
data={[...list,...this.state.newArr]}
renderItem={this.renderItem}
/>
<Button
title='Load More'
onPress={this.onScrollEndDrag}>
</Button>
</Fragment>
)
}
}
What can be done to show the new API data with the existing list?
Since you are anyways using async await no need of again using .then and .catch instead you can do it the below way.
onScrollEndDrag = async() => {
this.setState({ isSpinner: true });
try {
const response = await fetch(`myAPI`);
const json = await response.json();
this.setState({
newArr: [...this.state.newArr, ...(json || [])],
isSpinner: false
})
} catch(error) {
console.log(error);
this.setState({ isSpinner: false });
}
}
Hope this helps.

How to display multiple sets of data with reduce and promise.all in React

I'm making two calls from an API. I want to display the top results for airing shows and top tv shows. I have all of the data being returned from both API calls, but my code isn't efficient. I'd like to somehow take my returned data and display it in a single component (TopAnime) that will then map and return the information provided.
I figured reduce would be the best route, but I'm fumbling at this point. My thought process was to reduce the returned data from the API into an array. Take that reduced array and pass it as my new state and then have my component display it without having to write duplicate code. Both topTv and topAIring are showing because I've written the component twice, but it's clearly not best practice to repeat code.
class HomePage extends Component {
state = {
topTv: [],
topAiring: []
}
async getData() {
const api = "https://api.jikan.moe/v3"
const urls = [
`${api}/top/anime/1/tv`,
`${api}/top/anime/1/airing`
];
return Promise.all(
urls.map(async url => {
return await fetch(url) // fetch data from urls
})
)
.then(responses => // convert response to json and setState to retrieved data
Promise.all(responses.map(resp => resp.json())).then(data => {
console.log("data", data)
// const results = [...data[0].top, ...data[1].top]; // data from TV & data from airing
const reduceResults = data.reduce((acc, anime) => {
return acc + anime
}, [])
console.log('reduce', reduceResults);
const tvResults = data[0].top // data from TV
const airingResults = data[1].top // data from airing
this.setState({
topTv: tvResults,
topAiring: airingResults
});
})
)
.catch(err => console.log("There was an error:" + err))
}
componentDidMount() {
this.getData();
}
render() {
return (
<HomeWrapper>
<h2>Top anime</h2>
<TopAnime>
{this.state.topTv.map((ani) => {
return (
<div key={ani.mal_id}>
<img src={ani.image_url} alt='anime poster' />
<h3>{ani.title}</h3>
</div>
)
}).splice(0, 6)}
</TopAnime>
<h2>Top Airing</h2>
<TopAnime>
{this.state.topAiring.map((ani) => {
return (
<div key={ani.mal_id}>
<img src={ani.image_url} alt='anime poster' />
<h3>{ani.title}</h3>
</div>
)
}).splice(0, 6)}
</TopAnime>
</HomeWrapper>
)
}
}
Since the response from API contains a flag called rank you can use the Array.prototype.filter to only show shows ranked 1-6.
Working demo here
import React, { Component } from "react";
import { TopAnime } from "./TopAnime";
export class HomePage extends Component {
state = {
topTv: [],
topAiring: []
};
async getData() {
const api = "https://api.jikan.moe/v3";
const urls = [`${api}/top/anime/1/tv`, `${api}/top/anime/1/airing`];
return Promise.all(
urls.map(async url => {
return await fetch(url); // fetch data from urls
})
)
.then((
responses // convert response to json and setState to retrieved data
) =>
Promise.all(responses.map(resp => resp.json())).then(data => {
// if you care about mutation use this
const topTvFiltered = data[0].top.filter( (item) => item.rank <= 6 );
const topAiringFiltered = data[1].top.filter( (item) => item.rank <= 6 );
this.setState({
topTv: topTvFiltered,
topAiring: topAiringFiltered
});
})
)
.catch(err => console.log("There was an error:" + err));
}
componentDidMount() {
this.getData();
}
render() {
const { topTv, topAiring } = this.state;
return (
<React.Fragment>
{ topTv.length > 0 ? <h2>Top TV</h2> : null }
{this.state.topTv.map((item, index) => (
<TopAnime key={index} title={item.title} image={item.image_url} />
))}
{ topAiring.length > 0 ? <h2>Top airing</h2> : null }
{this.state.topAiring.map((item, index) => (
<TopAnime key={index} title={item.title} image={item.image_url} />
))}
</React.Fragment>
);
}
}

Need to use setstate() of data received from GraphQL subscription in react-apollo

I am trying to setState() of the GraphQL subscription Query that I am doing through react-apollo. My purpose is to store the complete the object that I received from GraphQL and save it into the state in the ComponentDidMount() method of the App.js file.
I have tried a lot of ways for it to work such as SubscribetoMore endpoint by react-apollo, but I think I am writing the wrong react code for it.
/App.js
const haveAnyFish = () => (
<Subscription subscription={gql`${SUBSCRIPTION_SYNC}`} >
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :</p>;
return (
<div>
<div>{fishes(data)}</div>
</div>
);
}}
</Subscription>
);
/App.js
class App extends React.Component {
state = {
fishes: {},
order: {}
};
componentDidMount() {
const fishes = (data) => {
this.setState({ fishes: data });
}
}
Subscription Query
const SUBSCRIPTION_SYNC = `
subscription syncState{
cotd {
_id_2
name
desc
image
price
status
}
}`;
You no need to have componentDidMount in your case. You have defined function inside componentDidMount method and that can’t be accessed outside
Change
componentDidMount() {
const fishes = (data) => {
this.setState({ fishes: data });
}
}
To
fishes = data => {
this.setState({ fishes: data });
}
And Change
const haveAnyFish = () => (
<Subscription subscription={gql`${SUBSCRIPTION_SYNC}`} >
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :</p>;
return (
<div>
<div>{this.fishes(data)}</div>
</div>
);
}}
</Subscription>
);
To
haveAnyFish = () => (
<Subscription subscription={gql`${SUBSCRIPTION_SYNC}`} >
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :</p>;
return (
<div>
<div>{this.fishes(data)}</div>
</div>
);
}}
</Subscription>
);
You must be calling haveAnyFish function in your component without this so after above code change you need to call haveAnyFish function using this.haveAnyFish
Also note that whenever you create functions inside a component they no need const before the function and if you want to access state or props inside those function you need to manually bind them or change them to arrow functions

Categories