How to retrieve a fetch data from a JSON? - javascript

In a React component
import React from 'react';
export default function Customers (props) {
const [customers, setCustomers] = React.useState([]);
React.useEffect(() => {
fetch("/data.json").then(response => response.json())
.then(data => {
setCustomers([data])
})
}, []);
return (
<div id='Customers'>
{customers.map(c => c.name)}
</div>
)
How can I display just the names of the customers from a file in the public directory called data.json ?
{
"customers": [
{
"id": 542,
"name": "E"
},
{
"id": 354,
"name": "V"
},
{
"id": 54534
"name": "A"
} ,
{
"id": 33,
"name": "K"
}
],
"packages": [
{
"id": 3643453453453,
"weight": 6343
},
{
"id": 453453,
"weight": 4534534534
}
]
}
I tried using customers["customers"] or customers.customers but nothing worked...
Thanks.

import React from 'react';
export default function Customers (props) {
const [data, setData] = React.useState({});
React.useEffect(() => {
fetch("/data.json").then(response => response.json())
.then(res => {
setCustomers(res)
})
}, []);
return (
<div id='Customers'>
{data && data.customers ? data.customers.map(c => c.name) : null}
</div>
)

I think you should change the React.useEffect to this
React.useEffect(() => {
fetch("/data.json")
.then(response => response.json())
.then(data => {
setCustomers(data.customers) //this is where I made the change
});
}, []);

Related

Avoid render the button after onClick

I'm trying to render some tags from a source and then put it into a buttons in random form but the issue comes after click the button my component re-render for no reason.
why can i do?...
const Blog = () => {
const [articles, setArticles] = useState([]);
const [tags, setTags] = useState([]);
// consult to database
const getData = async () => {
try {
// get aticles, tags
setArticles([
{ name: "title1", id_tag: 1 },
{ name: "title2", id_tag: 2 }
]);
setTags([
{ id: 1, name: "bell" },
{ id: 2, name: "fashion" }
]);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getData();
}, []);
const getRandomTag = (i) => {
const newTags = tags;
const tag = newTags[Math.floor(Math.random() * newTags.length)];
return (
<button key={i} onClick={() => filterByTag(tag.id)}>
{tag.name}
</button>
);
};
// filter the article by tag
const filterByTag = (id) => {
setArticles(articles.filter((article) => article.id_tag === id));
};
return (
<>
<ul>
{articles.map((article, i) => (
<li key={i}>{article.name}</li>
))}
</ul>
<h4>TAGS</h4>
<ul>{tags.map((tag, i) => getRandomTag(i))}</ul>
</>
);
export default Blog;
https://codesandbox.io/s/heuristic-solomon-sp640j?from-embed=&file=/src/Blog.js
That's because your component re-renders whenever any state inside it or any props it receives changes either by value or reference. And whenever you map something without caching its value it maps on each rerender. You have tu either split it into other component or use caching.
import { useCallback, useEffect, useMemo, useState } from "react";
const Blog = () => {
const [articles, setArticles] = useState([]);
const [tags, setTags] = useState([]);
// consult to database
const getData = async () => {
try {
// get aticles, tags
setArticles([
{ name: "title1", id_tag: 1 },
{ name: "title2", id_tag: 2 },
{ name: "title3", id_tag: 3 },
{ name: "title4", id_tag: 4 },
{ name: "title5", id_tag: 5 },
{ name: "title6", id_tag: 6 }
]);
setTags([
{ id: 1, name: "bell" },
{ id: 2, name: "fashion" },
{ id: 3, name: "fancy" },
{ id: 4, name: "tag" },
{ id: 6, name: "name" },
]);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getData();
}, []);
const filterByTag = useCallback((id) => {
setArticles(currentArticles => currentArticles.filter((article) => article.id_tag === id));
}, [setArticles]);
const getRandomTag = useCallback(
(i) => {
const newTags = tags;
const tag = newTags[Math.floor(Math.random() * newTags.length)];
return (
<button key={i} onClick={() => filterByTag(tag.id)}>
{tag.name}
</button>
);
},
[tags, filterByTag]
);
// filter the article by tag
const renderTags = useMemo(() => {
return tags.map((tag, i) => getRandomTag(i));
}, [tags, getRandomTag]);
return (
<>
<ul>
{articles.map((article, i) => (
<li key={i}>{article.name}</li>
))}
</ul>
<h4>TAGS</h4>
<ul>{renderTags}</ul>
</>
);
};
export default Blog;
Here you have a working example of caching https://codesandbox.io/s/sad-shadow-8pogoc?file=/src/Blog.js

Pagination with React & Axios: Iterating through array

I am using use-axios hooks in my React application to fetch data from an API and paginate it with 5 items each page.
Sandbox: https://codesandbox.io/s/axios-hooks-infinite-scrolling-forked-hxbnq?file=/src/index.js
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import useAxios from "axios-hooks";
function App() {
const [dataPerPage, setDataPerPage] = useState({});
const [page, setPage] = useState(1);
const [{ data, loading, error }] = useAxios({
url: "http://localhost:6366/api/rule-sets",
params: { page: page }
});
useEffect(() => {
setDataPerPage((d) => ({ ...d, [page]: data }));
}, [page, data]);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
return (
<div>
<button onClick={() => setPage((p) => p + 1)}>load more</button>
<pre>
{JSON.stringify(
[].concat(...Object.values(dataPerPage).map((p: any) => p)),
null,
2
)}
</pre>
</div>
);
}
The API is returning me this:
[
{
"user": {
"username": "q123123",
"displayName": "John Snow"
},
"active": false,
"_id": "612496f44683924ea85d731b",
"filename": "my file 2.xls",
"rules": [
{
"_id": "612496f44683924ea85d731c",
"sourceSystem": "CRM_MOBILE",
"classifications": "OPT,BLM",
"segment": null,
"calendar": "Standard",
"createSla": true,
"slaDurationInMinutes": 300,
"sendNotification": true,
"useHolidays": false
}
],
"createdAt": "2021-08-24T06:51:32.552Z",
"updatedAt": "2021-08-24T06:51:32.552Z",
"__v": 0
},
...
]
I want now to pass each object in the Array to my <RuleSetsItem> component as a prop:
<RuleSetsItem ruleSets={ruleSet} />
But I can not iterate it like this:
{ [].concat(...Object.values(dataPerPage).map((p: any) => (
p ? p.map(item => <RuleSetsItem>) : ''
)))}
as there is no map possible and also the first render is undefinded || null.
I also tried it with Object.keys(p).map() but this just returns me 01234.
This is my original implementation as reference before I implemented pagination with just a basic GET that returned me all stored items:
{ruleSets?.length
? ruleSets.map((ruleSet: RuleSetType) => (
<div key={ruleSet._id}>
<RuleSetsItem ruleSets={ruleSet} />
</div>
))
: ''}

How to make correct loop of JSON in React

I've got a problem with making a correct loop in React. I want to fetch data from JSON to don't repeat components. I tried to make two loops and then two maps, but everything was in bad order. The other problem is that "description" is also an array that's why I'm not able to deal with it
JSON:
{
"oswiecim": [
{
"header": "Oświęcim Zasole",
"description": [
"Rejon ulic św Maksymiliana Kolbego",
"i Stanisławy Leszczyńskiej"
]
},
{
"header": "Oświęcim Zasole",
"description": [
"Rejon ulic Więźniów Oświęcimia",
"Obozowej, Polnej i Legionów"
]
},
{
"header": "Stare Miasto",
"description": [
"Rejon Rynku i Placu ks. Jana Skarbka oraz ",
"ulic Zamkowej i Władysława Jagiełły"
]
},
{
"header": "Stare Miasto",
"description": [
"Cmentarz Parafialny oraz rejon",
"ul. Wysokie Brzegi."
]
},
{
"header": "Osiedle Chemików",
"description": [
"Największa pod względem liczby ludności",
"dzielnica Oświęcimia"
]
}
]
}
React:
import '../../styles/selection/Selection.scss'
import { useEffect, useState } from 'react';
const Selection = () => {
const [data, setData] = useState({})
const getData = async () => {
await fetch('https://jsoneditoronline.org/#left=cloud.b95a27020e1c45e9b3a7c95a74fc5d49', {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(res => res.json())
.then(data => {
setData(data)
})
}
useEffect(() => {
getData()
}, [])
const headers = []
const descriptions = []
for (const item of data.oswiecim) {
headers.push(item.header)
descriptions.push(item.description)
}
return (
<div className="selection">
{headers.map(item => (
<h1>{item}</h1>
))}
{descriptions.map(item => (
item.map(elem => (
<p>{elem}</p>
))
))}
</div>
);
}
export default Selection;
The result should look like this:
You don't need to separate header and description in two different variables.
So try something like this:-
return (
<div className="selection">
{data.oswiecim?.map((item) => (
<>
<h1>{item.header}</h1>
{item.description?.map((description) => (
<p>{description}</p>
))}
</>
))}
</div>
);
Live demo
Replace the setData(data); with following. It will just give the array you need to iterate,
setData(data.oswiecim);
Remove the following code,
const headers = []
const descriptions = []
for (const item of data.oswiecim) {
headers.push(item.header)
descriptions.push(item.description)
}
Replace return statement with following,
<div className="selection">
{data &&
data.map(item => (
<>
<div>{item.header}</div>
{item.description &&
item.description.map(descriptionItem => <p>{descriptionItem}</p>)}
</>
))}
</div>

ReactJS mapping to API

import React, { Component } from 'react';
import axios from 'axios';
class Meetups extends Component {
constructor(props) {
super(props);
console.log('in constructor');
this.state = {
results: [],
};
}
componentDidMount() {
console.log('meetup feed');
axios.get('https://api.meetup.com/2/categories?offset=0&format=json&photo-host=public&page=20&order=shortname&desc=false&sig_id=211627025&sig=ae69aec13f23c7837cd55c5a68b99e00719fa225')
//response
.then(response => response.json())
.then(data => this.setState({results:data.results}));
}
render() {
const {results} =this.state;
return(
<div>
{results.map(result =>
<div key={result.id} className='container'>
{result.name}
</div>
)}
</div>
);
}
}
export default Meetups;
JSON format which I'm receiving:
{
"results": [
{
"name": "Arts & Culture",
"sort_name": "Arts & Culture",
"id": 1,
"shortname": "Arts"
},
{
"name": "Book Clubs",
"sort_name": "Book Clubs",
"id": 18,
"shortname": "Book Clubs"
},
{
"name": "Career & Business",
"sort_name": "Career & Business",
"id": 2,
"shortname": "Business"
}
]
}
I am trying to use Meetup API in my project. But could not able to connect with it. There might be a problem with mapping. I want to know exact mapping for the given json format. Please help me out. Thanks
import React, { Component } from 'react';
import axios from 'axios';
class Meetups extends Component {
state = {
results: []
}
componentDidMount() {
axios.get('https://api.meetup.com/2/categories?offset=0&format=json&photo-host=public&page=20&order=shortname&desc=false&sig_id=211627025&sig=ae69aec13f23c7837cd55c5a68b99e00719fa225')
.then(response => {
let results = response.data.results;
this.setState({ results: results });
console.log(response);
})
}
render() {
let studentsDisplay = (
this.state.results.map( (result, index) =>
<div key={index} className="card" style= { {width: '18rem'} }>
{result.name}
<br/>
{result.shortname}
</div>
));
return (
<div className='container'>
{
studentsDisplay
}
</div>
);
}
}
export default Meetups;

How to update fetched data to view next or previous page - Paginated

I am fetching data from a API,then displaying it to the page. I have achieved that,
Now I want to build a next and previous button to render the next page of information.
One of the data returned is metadata to links that can be attached to the base url. I got the data and updated it in my state as:
articlePages: []
the data is structured as :
"metadata": {
"pagination": {
"next_page": "/api/articles/ios_index?page=2",
"current_page": "/api/articles/ios_index?page=1",
"previous_page": "/api/articles/ios_index?page=0"
}
}
How should I build the functions for previous and next, so that they attach the right string to the base url, then fetch the new data?
Here is the response I receive then I update my state:
Response Format:
"metadata": {
"pagination": {
"next_page": "/api/articles/ios_index?page=2",
"current_page": "/api/articles/ios_index?page=1",
"previous_page": "/api/articles/ios_index?page=0"
}
}
"data" :{
"id": 713,
"url": "https:sample.-sale",
"title": "The World According to Eddie Huang",
"published_at": "2017-08-29T04:00:00.000Z",
"published": true,
"hero": "https://d1qz9pzgo5wm5k./CPG9crJHRqSPKQg9jymd",
"listings": [],
"tag_list": [
"eddie-huang",
"television"
],
"franchise": "The Drop",
"slug": "eddie-huang-interview-sale",
"author": "Lawrence Schlossman",
"content_type": "long",
"position": "feature"
}
Here is a snippet of my code, any help is appreciated :
import React from 'react';
import axios from 'axios';
export default class ArticleApi extends React.Component {
constructor() {
super();
this.state = {
blogs: "",
articlePages: []
}
}
fetchData = () => {
axios.get(`https:sample.sale/api/articles/ios_index`)
.then(res => {
this.setState({
blogs: res.data.data,
blogPages: res.data.metadata
})
})
.catch(error => {
return ('Looks like there was a problem: \n', error);
});
}
componentDidMount() {
this.fetchData()
}
previousPage = () => {
axios.get(`https:sample.sale/api/articles/ios_index${this.state.blogPages.pagination.previous_page}`)
.then(res => {
this.setState({
blogs: res.data.data,
blogPages: res.data.metadata
})
})
.catch(error => {
return (error);
});
}
nextPage = () => {
axios.get(`https:sample.sale/api/articles/ios_index${this.state.blogPages.pagination.next_page}`)
.then(res => {
this.setState({
blogs: res.data.data,
blogPages: res.data.metadata
})
})
.catch(error => {
return (error);
});
}
render() {
let feed = "Loading...";
if (this.state.blogs) {
feed = this.state.blogs.map((ele, idx) => {
return (
<div key={idx} >
<div className="articleContent">
<p><strong>{ele.franchise}</strong></p>
<h1 className="title"> {ele.title}</h1>
</div>
</div>
)
})
}
return (
<div>
<h3 FEED</h3>
{feed}
<button onClick={this.previousPage}>Previous Page</button>
<button onClick={this.nextPage}>Next Page</button>
</div>
)
}
}
At present you are building a strange URL for both the next and previous page functions:
axios.get(`https:sample.sale/api/articles/ios_index${this.state.blogPages.pagination.next_page}`)
// but this.state.blogPages.pagination.next_page is equal to "/api/articles/ios_index?page=2", right?
// So if we replace the variable with its value, your url actually looks something like this:
axios.get('https:sample.sale/api/articles/ios_index/api/articles/ios_index?page=2')
The correct call should look like:
axios.get(`https:sample.sale${this.state.blogPages.pagination.next_page}`)
And similarly for previous page.

Categories

Resources