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>
))
: ''}
Related
Hi I'm currently working on a react native app and I'm trying to get a users playlist and then return it in a flatlist. I've completed getting a users access_token but I'm a little stuck on figuring out how to actually use the data. I'm fairly new to using api data.
export default function SpotifyGetPlaylist(props) {
const { colors } = useTheme();
const [token, setToken] = useState('');
const [data, setData] = useState({});
React.useEffect(() => {
getData();
}, []);
const getData = async() => {
setToken (await AsyncStorage.getItem('#access_token'));
console.log("token retrieved")
}
const handleGetPlaylists = () => {
axios.get("https://api.spotify.com/v1/me/playlists", {
headers: {
Authorization: `Bearer ${token}`,
},
}).then(response => {
setData(response.data);
console.log(response.data)
})
.catch((error) => {
console.log(error);
});
};
}
This part works fine and returns data into the console as such
Object {
"collaborative": false,
"description" : "Maailman – Päivittäinen katsaus siihen, mitä kappaleita kuunnellaan eniten juuri nyt.",
"external_urls": Object {
"spotify": "https://open.spotify.com/playlist/37i9dQZEVXbMDoHDwVN2tF",
},
"href" : "https://api.spotify.com/v1/playlists/37i9dQZEVXbMDoHDwVN2tF",
"id" : "37i9dQZEVXbMDoHDwVN2tF",
"images": Array [
Object {
"height": null,
"url" : "https://charts-images.scdn.co/assets/locale_en/regional/daily/region_global_large.jpg",
"width" : null,
},
],
"name": "Maailman – Top 50",
"owner": Object {
"display_name" : "Spotify",
"external_urls": Object {
"spotify": "https://open.spotify.com/user/spotify",
},
"href": "https://api.spotify.com/v1/users/spotify",
"id" : "spotify",
"type": "user",
"uri" : "spotify:user:spotify",
},
"primary_color": null,
"public" : true,
"snapshot_id" : "NzAzNDIxMzk0LDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDY2Njk=",
"tracks": Object {
"href" : "https://api.spotify.com/v1/playlists/37i9dQZEVXbMDoHDwVN2tF/tracks",
"total": 50,
},
"type": "playlist",
"uri" : "spotify:playlist:37i9dQZEVXbMDoHDwVN2tF",
},
But I'm having problems actually rendering anything into the Flatlist which at the moment looks like this.
const renderItem = ({item}) => {
<Item title={item.name}/>
}
return (
<View style={styles.container}>
<Button
onPress = {handleGetPlaylists}
color = "#1DB954"
style = {{ color: colors.text, width: 100 }}
title = "Get your playlists"/>
<FlatList
data = {data}
renderItem = {renderItem}
keyExtractor= {(item) => item.id.toString()}
/>
</View>
)
I'm unsure how I get the data from the api my hunch is that I would have to use data.items.name to access it but it doesnt work for me. Help is much appreciated
Nothing is appearing in the FlatList render because you're not returning your Item. Because you have curly braces around the body of the function, you have to explicitly return the component.
const renderItem = ({item}) => {
return <Item title={item.name} />;
}
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
});
}, []);
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>
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
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