How to access more complex nested data JSON in REACT - javascript

I'm trying to render a row of 10 books and a row of 10 movies from my component which would look like rows in netflix to give you an idea. I've shortened the json bellow. I'm able to fetch and access my data and save it in useState of the component. Although I'm not able to render. Lack of experience. I've paste result in both console.log bellow react component. Help would be welcome please!!!
JSON file
[
{
"id": 1,
"rowTitle": "Books",
"row": [
{
"id": 1,
"title": "Book1",
"desc": "Book1 description",
"url": "images/books/Book1.jpeg"
},
{
"id": 2,
"title": "Book2",
"desc": "Book2 description",
"url": "images/books/Book2.jpeg"
},
]
},
{
"id": 2,
"rowTitle": "Movies",
"row": [
{
"id": 1,
"title": "movie1",
"desc": "movie1 description",
"url": "images/movies/movie1.jpeg"
},
{
"id": 2,
"title": "movie2",
"desc": "movie2 description",
"url": "images/movies/movie2.jpeg"
},
]
}
]
React component
import { Link } from 'react-router-dom';
import { Caroussel, RowSlider, SliderContainer, Title } from './Home.styled';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
const Home = () => {
const [data, setData] = useState([]);
const getData = () => {
fetch('data/projects.json', {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
})
.then((response) => {
console.log(response);
return response.json();
})
.then((myJson) => {
console.log(myJson);
setData(myJson);
});
};
useEffect(() => {
getData();
}, []);
const settings = {
dots: false,
infinite: false,
speed: 1000,
slidesToShow: 2,
slidesToScroll: 2,
// lazyLoad: 'progressive',
};
return (
<>
<RowSlider>
<Title>
{data.map((obj) => {
console.log(obj);
// RESULT -> Object { id: 1, rowTitle: "Books", row: (10) […] }
return <h1>{obj.rowTitle}</h1>;
// -> RESULT but this render at the same time both titles (BOOKS and MOVIES), and I need to render BOOKS title first then its books row before rendering next row, MOVIES title and its movies..
})}
</Title>
<SliderContainer>
<Caroussel {...settings}>
{data &&
data.map((slide) => {
console.log(slide);
// RESULT -> Warning: Each child in a list should have a unique "key" prop. ** BUT not event sure event if they was an it would still be working
return (
<div key={slide.id}>
<div className="slick-slide">
<img
className="slick-slide-image"
alt={slide.title}
src={slide.url}
/>
<h2 className="slick-slide-title">{slide.title}</h2>
</div>
<Link to="/stations">
<div className="slick-slide-filter"> </div>
</Link>
</div>
);
})}
</Caroussel>
</SliderContainer>
</RowSlider>
</>
);
};
// {/* <label className="slick-slide-label">{slide.label}</label> */}
export default Home;

Your data is an array of objects so you a) need to iterate (map) over them, and then b) map over the row array inside those objects to build the HTML.
function Example({ data }) {
function getJSX(data) {
// `map` over the array and for each object
// return the rowTitle, and also `map` over
// each object in `row` and return some markup
return data.map(obj => {
return (
<div key={obj.id}>
<h4>{obj.rowTitle}</h4>
{obj.row.map(row => {
return <div>{row.title}: {row.desc}</div>;
})}
</div>
);
});
}
return (
<div>
{getJSX(data)}
</div>
);
};
const data=[{id:1,rowTitle:"Books",row:[{id:1,title:"Book1",desc:"Book1 description",url:"images/books/Book1.jpeg"},{id:2,title:"Book2",desc:"Book2 description",url:"images/books/Book2.jpeg"}]},{id:2,rowTitle:"Movies",row:[{id:1,title:"movie1",desc:"movie1 description",url:"images/movies/movie1.jpeg"},{id:2,title:"movie2",desc:"movie2 description",url:"images/movies/movie2.jpeg"}]}];
ReactDOM.render(
<Example data={data} />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Related

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>

Calling json postData properly

Hello stackoverflow members. So I wanna call this action nested array in json to Action Component but I dont know how. If I could get some help that would be highly appriciated
import React from 'react'
import data from "../data.json";
function Action() {
return (
<div>
{data.map((postData) => {
console.log(postData);
return(
<div key={postData.id}>
<h1 >{postData.action.name}</h1>
</div>
)})}
</div>
)
}
export default Action
[
{
"action":[{
"id":"0",
"image": "src=fsdf",
"price" : "60$",
"name" :"cs"
},
{
"id":"1",
"image": "src=fsdf",
"price" : "6$",
"name" :"whatever"
}],
"adventure":[{
"id":"10",
"image": "src=fsdf",
"price" : "60$",
"name" :"Cs"
}]
}
]
You need to store your data.json file in the public folder if you want to access the data in json format and then make use of useEffect Hook and fetching data within useEffect() Hook itself to get the data.
Here is the WORKING DEMO on Codesandbox:
https://codesandbox.io/s/json-fanda-stydg
FULL CODE:
import React from "react";
import { useEffect, useState } from "react";
import "./styles.css";
function App() {
const [data, setData] = useState([]);
useEffect(() => {
fetch("./data/data.json")
.then((response) => response.json())
.then((json) => {
console.log(json);
setData(json);
});
});
return (
<div>
{data.length > 0 &&
data.map((postData) => {
console.log(postData);
return (
<div key={data.id}>
{postData.action.map((action) => {
return <h1>{action.name}</h1>;
})}
<p>
{postData.adventure.map((adventure) => {
return <h1>{adventure.name}</h1>;
})}
</p>
</div>
);
})}
</div>
);
}
export default App;
JSON: You JSON is perfectly fine :)
[
{
"action": [
{
"id": "0",
"image": "src=fsdf",
"price": "60$",
"name": "cs"
},
{
"id": "1",
"image": "src=fsdf",
"price": "6$",
"name": "whatever"
}
],
"adventure": [
{
"id": "10",
"image": "src=fsdf",
"price": "60$",
"name": "Cs"
}
]
}
]
You could change your code to something like this:
import data from "../data.json";
//...
export default function App() {
return (
<div className="App">
<div>
{data[0].action.map((postData) => {
return (
<div key={postData.id}>
<h1>{postData.name}</h1>
</div>
);
})}
</div>
</div>
);
}
data is an array with one object with two properties: action and adventure that are arrays.
As prasanth points out given your current data you could also remove the outer most array and make data a single object.
Then you can just map over data.action.
sandbox

React hook form useEffect not re-rendering functional component with call to another component

I'm trying to do a a react form using react-hook-forms, but I'm having trouble presenting data retrieved from an API call.
I've sort of combined this example, which deals with asynchronously setting form values, and this example, which deals with nested arrays.
But for the life of me, I simply could not get it to work. The JSON output of the API is something like this:
{"daily": { "last_received_date": "2020-08-03 11:04:18 UTC+8", "tasks": [
{ "id": "1", "freq": "d", "prog": 0, "max": 5, "reward": 1000 },
{ "id": "2", "freq": "d", "prog": 0, "max": 1, "reward": 1000 },
{ "id": "3", "freq": "d", "prog": 0, "max": 3, "reward": 1000 }]},
"weekly": {/*Similar to daily*/}}
Here's the functional component:
const UserTaskForm = (data) => {
const [TaskId, setTaskId] = useState();
const [TaskArray, setChallengeArray] = useState([]);
const { register, control, handleSubmit, getValues, reset, errors } = useForm();
const onSubmit = (formData) => {console.log(formData);};
useEffect(() => {
async function fetchData() {
try {
let result = await dbGetUserTasks(data.userId);
console.log(result);
const tempArray = [];
const formData = JSON.parse(result[0].challenges);
tempArray.push(formData.daily);
tempArray.push(formData.weekly);
setTaskId(JSON.parse(result[0].id));
setChallengeArray(tempArray);
} catch (error) { console.error(error); }
}
fetchData();
}, []);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Box paddingTop={2} paddingBottom={2}>
<Button type="submit" style={{ marginLeft: "auto" }}>Save Changes</Button>
</Box>
{TaskArray ? <Spinner animation="border" /> : <TaskTypeCards{...{ control, register, TaskArray, getValues, errors }} />}
</form>
);
}
export default UserTaskForm;
And here's the functional component that calls:
export default function TaskTypeCards({ control, register, defaultValues, errors }) {
console.log(defaultValues); // <--------------- Undefined.
const { fields, append, remove } = useFieldArray({ control, name: "test" });
useEffect(() => {
console.log(defaultValues); // <--------------- Undefined.
}, [defaultValues])
return(
{defaultValues.map((challenge, index) => {
return (
<Card>
Blah blah this doesn't work anyway
</Card>
)
})}
)
}
I understand that the components are rendered before the useEffect is fired in UserTaskForm, but how do I re-render it, such that defaultValues in TaskTypeCards don't log out an undefined?
defaultValues need to be passed as the props , to receive it as props in the TaskTypeCards components.
Thanks

How to write 2 fetch method for contact API and Message API in reactjs?

I'm new to reactjs. I could map the data from json API. My objective is when we save a number in contactlist, it should show the name in message list also. I want to create 2 fetch data i.e., messageData, ContactData that should compare the Phone numbers of message API and COntact API. If Phone number is same in contact API and Message API then it should return name otherwise it should return only phone number.
Contact json data would be like
[
{
"id": 1,
"name": "ABC",
"phone": "+91 789654123",
"email": "abcyz#gmail.com"
},
{
"id": 2,
"name": "DEF",
"phone": "+91 123456987",
"email": "defvu#gmail.com"
}
]
Contact Component:
import React, { Component } from "react";
import { Grid, Header, Button, Icon } from "semantic-ui-react";
import { Link } from 'react-router-dom'
class ComponentList extends Component {
state = {
peopleData: []
};
componentDidMount() {
fetch('./people.json')
.then(response => response.json())
.then(data => this.setState({ peopleData: data }));
}
pnum(num) {
return num.replace(/^\D/g, "");
}
render() {
const {peopleData} = this.state;
return(
<div>
{ peopleData.map(people =>
<Grid>
<Grid.Row key={people.id}>
<Grid.Column>
<Header>{people.name}</Header>
<span>{people.phone}</span>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Button trigger={<Link to={`/displayChat/${this.pnum(people.phone)}`}>
<Icon name='comment alternate outline' color='teal' /></Link>}/>
</Grid.Row>
</Grid>
)}
</div>
);
}
}
export default ComponentList;
Message API:
[
{
"id": 1,
"phone": "+91 789654123",
"message": "Hello everyone",
"isrespond": true,
},
{
"id": 2,
"phone": "+91 123456987",
"message": "hi",
"isrespond": false,
}
]
DisplayChat component:
fetchChat() {
const { phone } = this.props.match.params ;
fetch(`api/conversation/${phone}`)
.then(response => response.json())
.then(data => this.setState({ messageList: data})
);
}
render(){
const {messageList} = this.state;
const { phone } = this.props.match.params ;
return(
<div>
<ViewHeader phone={this.props.match.params}/>
<Container className="viewMessage ">
{messageList.map(data =>
<Grid>
<Grid.Row key={data.id}>
<p>{data.message}</p>
</Grid.Column>
</Grid.Row>
</Grid>
)}
</Container>
<TypeHere phone={this.props.match.params}/>
</div>
);
}
}
Can anyone help me in this?
const URL1= "contactApi"
const URL2= "messageApi"
I have used promise.all along with fetch to resolve both the endpoints
Promise.all([
fetch(URL1),
fetch(URL2),
]).then(responses => responses
).then(responses => Promise.all(responses.map(r => r.json())))
.then(data=>writeLogic(data));
function writeLogic(data){
let nameOrPhone;
const contactApiData = data[0]
const messageApiData = data[1]
let isPresent
for(let m of messageApiData){
isPresent=false
for(let c of contactApiData){
if(m.phone === c.phone){
isPresent=true
nameOrPhone.push(c.name)
}
}
if(!isPresent){
nameOrPhone.push(m.phone)
}
}
//update your state here if you are using React
//this.setState({nameOrPhone})
console.log(nameOrPhone)
}
data will contain result of both the endpoint in an array.
you can use the data and write your logic on top of it.
Ref: https://javascript.info/promise-api

Categories

Resources