Reputation: 151
I'm trying to Cycle through my data I'm getting back from an API Call. If I use dummy data in an array, it will cycle fine. But once I attempt to place my api data in its place, it just shows all the items at once instead of cycling one at a time. I console.log(items.length)
and get 1
which tells me that this is an array of an object and is just reading it as a whole. Could use some help getting this displaying one item at a time instead of the whole thing at once.
API Call(Title.js):
import { Component, React } from "react";
//import TitleCycle from '../components/TitleCycle';
let headers = {
"QB-Realm-Hostname": "XXXXXXXXXX.quickbase.com",
"User-Agent": "FileService_Integration_V2.1",
"Authorization": "QB-USER-TOKEN XXXXXXX_XXXX_XXXXXXXX",
"Content-Type": "application/json"
};
class Title extends Component {
state = {
data: null
};
componentDidMount() {
this.fetchData();
}
fetchData = () => {
let body = {"from":"bpz99ram7","select":[3,6,40],"where": "{40.CT. 'In Progress'}","sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":40,"grouping":"equal-values"}],"options":{"skip":0,"top":0,"compareWithAppLocalTime":false}};
fetch("https://api.quickbase.com/v1/records/query", {
method: "POST",
headers: headers,
body: JSON.stringify(body)
})
.then((response) => response.json())
.then((data) => this.setState({ data }));
};
render() {
const { data } = this.state;
if (data === null) return "Loading Job Data...";
return (
<div className="Title">
{Object.keys(data["data"]).map(item => (
<div key={item}>
{data["data"][item][6].value}
</div>
))}
</div>
);
}
}
export default Title;
TitleCycle.js:
import React from "react";
import Title from "./header/Title";
const items = [
// {name: "Job Name One"}, {name: "Job Name Two"}, {name: "Job Name Three"},
<Title/> //Problem is here because this is showing as an object of objects? Needs to be an array
];
console.log(items.length)
//console.log(items.length) this shows 1, meaning only one item with multiple objects...
export default function TitleCycle() {
const [titleData, setTitleData] = React.useState(items[0]);
const [index, setIndex] = React.useState(0);
// Set Timer and Interval based on Index
React.useEffect(() => {
const timerId = setInterval(
() => setIndex((i) => (i + 1) % items.length),
2000 // 2 seconds.
);
return () => clearInterval(timerId);
}, []);
// Set TitleData with Index
React.useEffect(() => {
setTitleData(items[index]);
}, [index]);
return (
<div className="TitleCycle">
<h3>{titleData}</h3>
</div>
);
}
{
"data": [
{
"3": {
"value": 177
},
"6": {
"value": "2220 Three Kings "
},
"40": {
"value": "In Progress"
}
},
{
"3": {
"value": 302
},
"6": {
"value": "529 Woodsview"
},
"40": {
"value": "In Progress"
}
},
{
"3": {
"value": 9
},
"6": {
"value": "7948 Red Tail"
},
"40": {
"value": "In Progress"
}
}
Any help would be appreciated!
The issue is that it is reading as 1 item, but because my api is reading as an object of objects, instead of an array. I'm ultimately trying to send this data over to TitleCycle.js to cycle through and display each one in a duration at a time.
UPDATE: My issue seems to be how I'm attempting to send <Title />
from Title.js to TitleCycle.js to use the API Response as the items array in question.
I'm trying to do the API call in one file, send that array over to TitleCycle.js to cycle based on duration.
Upvotes: 1
Views: 102
Reputation: 203466
If you've an array of objects then you need to pick out the object properties you want rendered.
For a given element object:
{
"3": {
"value": 177
},
"6": {
"value": "2220 Three Kings "
},
"40": {
"value": "In Progress"
}
}
Select one of the "3"|"6"|"40"
property's value
property to render:
function TitleCycle() {
const [titleData, setTitleData] = React.useState(items[0]);
const [index, setIndex] = React.useState(0);
// Set Timer and Interval based on Index
React.useEffect(() => {
const timerId = setInterval(
() => setIndex((i) => (i + 1) % items.length),
2000 // 2 seconds.
);
return () => clearInterval(timerId);
}, []);
// Set TitleData with Index
React.useEffect(() => {
setTitleData(items[index]);
}, [index]);
return (
<div className="TitleCycle">
<h3>{titleData["6"].value}</h3>
</div>
);
}
You could also save the extra state and render cycle by consuming the updated index instead.
function TitleCycle() {
const [index, setIndex] = React.useState(0);
// Set Timer and Interval based on Index
React.useEffect(() => {
const timerId = setInterval(
() => setIndex((i) => (i + 1) % items.length),
2000 // 2 seconds.
);
return () => clearInterval(timerId);
}, []);
return (
<div className="TitleCycle">
<h3>{items[index]["6"].value}</h3>
</div>
);
}
It seems you need to render the TitleCycle
component in Title
instead of the divs with the titles.
class Title extends Component {
state = {
data: null,
};
componentDidMount() {
this.fetchData();
}
fetchData = () => {
let body = {"from":"bpz99ram7","select":[3,6,40],"where": "{40.CT. 'In Progress'}","sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":40,"grouping":"equal-values"}],"options":{"skip":0,"top":0,"compareWithAppLocalTime":false}};
fetch("https://api.quickbase.com/v1/records/query", {
method: "POST",
headers: headers,
body: JSON.stringify(body)
})
.then((response) => response.json())
.then(({ data }) => this.setState({ data })); // <-- destructure data from response
};
render() {
const { data } = this.state;
if (data === null) return "Loading Job Data...";
return (
<div className="Title">
<Titlecycle data={data} /> // <-- pass data
</div>
);
}
}
Access the passed data
prop and render. Conditionally render the titles only if the data
array has a truthy length (i.e. non-zero length).
function TitleCycle({ data }) { // <-- destructure data
const [index, setIndex] = React.useState(0);
// Set Timer and Interval based on Index
React.useEffect(() => {
const timerId = setInterval(
() => setIndex((i) => (i + 1) % data.length),
2000 // 2 seconds.
);
return () => clearInterval(timerId);
}, [data]); // <-- handle if data array prop changes
return data.length ? (
<div className="TitleCycle">
<h3>{data[index]["6"].value}</h3>
</div>
) : null;
}
Upvotes: 1
Reputation: 204
I don't think you should or can pass the prop as key
.
Try doing your Array.map
with two parameters (item, index)
Then make the key={index}
and pass the item as a prop to the actual component not a div:
<TitleCycle item={item} ....
EDIT
Additionally you can destructure the props object that gets passed to TitleCycle:
export default const TitleCycle = ({ item }) => {
//Now item === the individual top-level object for each component
}
Upvotes: 0