I'm trying to figure out the best way to loop through this data, right now I'm getting all 'Job Names' that are the id of 6 from my API. What I'd like to do is only show one at a time for 20 seconds or so, then move to the next only showing one at a time but continuously looping through all.
Any suggestions?
Here is one api call getting the titles of Job Names:
import { React, Component } from 'react';
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXX_XXXXX_XXXXXXXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class Title extends Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
this.fetchData();
}
fetchData = () => {
let body = {"from":"bpz99ram7","select":[3,6,80,81,82,83,86,84,88,89,90,91,92,93,94,95,96,97,98,99,101,103,104,105,106,107,109,111,113,115,120,123,224,225,226,227,228,229,230,231,477,479,480,481],"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}>
<h2>
{data["data"][item][6].value}
</h2>
</div>
))}
</div>
)
}
}
export default Title;
UPDATE: So after some researching I'm seeing some ideas on what I'm looking to do. like so:
let data = ['Job Name 1',
'Job Name 2',
'Job Name 3',
'Job Name 4',
'Job Name 5',
'Job Name 6',
'Job Name 7',
'Job Name 8',
'Job Name 9',
'Job Name 10'];
let interval = 2000; //I'll set to twenty seconds in production...
data.forEach((data, index) => {
setTimeout(() => {
console.log(data)
}, index * interval)
})
Similar to this, but Set this to loop continuously, so after 10, go back to 1. Is this where I'd use setInterval() instead of setTimeout()?
Once I get this set in accurately, I'd like to set LineCharts up that will populate based on what Title(Job Name) is displaying, changing when the Title does automatically...
UPDATE wanted to update to show How i've set the cycle in for my Job Names in my App.js, and sending this as a prop to my Title.js:
App.js
import React, { useEffect, useState } from "react";
import './App.css'
import Title from './components/header/Title'
import TotalLineChart from './components/charts/TotalLineChart'
import RadiantLineChart from './components/charts/RadiantLineChart'
import PlumbingLineChart from './components/charts/PlumbingLineChart'
import SnowmeltLineChart from './components/charts/SnowmeltLineChart'
import HVACLineChart from './components/charts/HVACLineChart'
import GasPipeLineChart from './components/charts/GasPipeLineChart'
import FixturesLineChart from './components/charts/FixturesLineChart'
// import TitleCycle from './components/TitleCycle'
// import Logo from './components/Logo';
let headers = {
"QB-Realm-Hostname": "XXXXXXXXX.quickbase.com",
"User-Agent": "FileService_Integration_V2.1",
"Authorization": "QB-USER-TOKEN XXXXXXXXX",
"Content-Type": "application/json",
"Retry-After": 120000
};
function App() {
const [allData, setAllData] = useState([]);
const [index, setIndex] = useState(0);
// Fetch all data, all jobs
useEffect(() => {
function 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 }) => setAllData(data));
}
fetchData();
}, []);
// Cycle through the jobIds and indexes
useEffect(() => {
const timerId = setInterval(
() => setIndex((i) => (i + 1) % allData.length),
5000 // 5 seconds.
);
return () => clearInterval(timerId);
}, [allData]);
// console.log(allData)
// console.log(index)
// Calculate info based on index
const jobId = allData[index]?.['3']?.value || '291'; // Default 291
const title = allData[index]?.['6']?.value || 'Default Title';
// console.log(jobId)
return (
<div>
{/* <div className="flexbox-container">
<div className="Logo">
{/* <Logo /> */}
{/* </div> */}
<div className="App">
<Title title = {title} />
</div>
<div className="TopChart">
<TotalLineChart jobId = {jobId} />
</div>
<div className="FirstRowContainer">
{/* <RadiantLineChart jobId = {jobId} /> */}
<PlumbingLineChart jobId = {jobId} />
<FixturesLineChart jobId = {jobId} />
</div>
<div className="SecondRowContainer">
<SnowmeltLineChart jobId = {jobId} />
<HVACLineChart jobId = {jobId} />
<GasPipeLineChart jobId = {jobId} />
</div>
</div>
);
}
export default App;
Title.js
import React from 'react'
function Title(props) {
const { title } = props;
return (
<div>
{ title }
</div>
)
}
export default Title
This allows the cycle and show one at a time based on the duration set in App.js.
I am not sure how your data looks like, but below is my closest guess.
import { React, Component } from 'react';
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXX_XXXXX_XXXXXXXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class Title extends Component {
constructor(props) {
super(props);
this.state = {
data: null,
displayItem : ''
};
this.dataInterval;
}
componentDidMount() {
this.fetchData();
}
startShowingData(data) {
let counter = 0;
let dataKeys = Object.keys(data["data"])
this.dataInterval = setInterval(() => {
this.setState({...this.state, displayItem: data[dataKeys[counter]]});
counter++; // you have to reset this counter at your wish or you have to do clearInterval(this.dataInterval) after array is completely traversed.
}, 20000)
}
fetchData = () => {
let body = {"from":"bpz99ram7","select":[3,6,80,81,82,83,86,84,88,89,90,91,92,93,94,95,96,97,98,99,101,103,104,105,106,107,109,111,113,115,120,123,224,225,226,227,228,229,230,231,477,479,480,481],"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.startShowingData(data.data));
}
render() {
const { data } = this.state;
if (data === null) return 'Loading Job Data... ';
return (
<div className="Title">
<h2>
{this.state.displayItem}
</h2>
</div>
)
}
}
export default Title;
Related
I've been trying to render a component using map, the render happens but with a warning:
Warning: unstable_flushDiscreteUpdates: Cannot flush updates when
React is already rendering.
MyBooks.js
import React, { useState, useEffect } from 'react';
import ActionAreaCard from '../components/ActionAreaCard';
const MyBooks = ({address}) => {
const [metadata, setMetadata] = useState([]);
const URL = `http://localhost:3001/api/tatumapi`;
const chain = 'CELO';
const params = { address: address, chain: chain };
useEffect(() => {
fetch(URL,
{
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})
.then(response => response.json())
.then(data => setMetadata(
(data.data).map((data2) => {
return data2.metadata.map((data3) => {
return data3;
})
})
))
}, [])
return (
<div>
{metadata.map((data4) => {
return (
<div>
{data4.map(({metadata}) => {
return (
<div>
{metadata!= null && console.log(metadata)}
{metadata!=null && <ActionAreaCard name={metadata.name} description={metadata.description} image={metadata.image}/>}
</div>
)
})}
</div>
)
})}
</div>
)
}
export default MyBooks;
Console output:
{description: 'The very first edition', name: 'BOOK', image: 'ipfs://bafkreidny67q3xxjulstouk7vzp6bomdbnokg3zzhg6k4gqbdtutqzz5h4'}
description: "The very first edition"
image: "ipfs://bafkreidny67q3xxjulstouk7vzp6bomdbnokg3zzhg6k4gqbdtutqzz5h4"
name: "BOOK"
[[Prototype]]: Object
Why I'm getting this warning and how can I solved it?
I've just improved the mapping and added a key.
import React, { useState, useEffect } from 'react';
import ActionAreaCard from '../components/ActionAreaCard';
const MyBooks = ({address}) => {
const [metadata, setMetadata] = useState([]);
const URL = `http://localhost:3001/api/tatumapi`;
const chain = 'CELO';
const params = { address: address, chain: chain };
useEffect(() => {
fetch(URL,
{
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})
.then(response => response.json())
.then(data => setMetadata(data.data.map(data2 => {
return data2;
})))
}, [])
return(
<div>
{metadata!=undefined && metadata!=null && metadata.map((data) => {
return data.metadata.map(({metadata}, i) => {
return (
<div key={i}>
{metadata!==null && <ActionAreaCard name={metadata.name} description={metadata.description} image={metadata.image}/>}
</div>
)
})
})}
</div>
)
}
export default MyBooks;
I have been doing js for about a month now, and I am writing this program where I am using clarifai API to see which celebrity a person on the photo resembles the most.
I want to pass the output as props to Rank component to render it, but
I get the
Type error: clarifaiResults.map is not a function at App.transformResponse
Basically, the response I want to pass as props is the
const clarifaiResults = response.outputs[0].data.regions[0].data.concepts[0].name;
part that I get in console.log now
I am assuming it's because there is no output yet when the app tries to render the component, but I can't figure out what's wrong with the code. Thank you!
App.js
import React, { Component } from 'react';
import './App.css';
import SignIn from './Component/SignIn/SignIn.js';
import Register from './Component/Register/Register.js';
import Particles from 'react-particles-js';
import Logo from './Component/Logo/Logo.js';
import Navigation from './Component/Navi/Navigation.js';
import ImageLinkForm from './Component/Form/ImageLinkForm.js';
import Rank from './Component/Rank/Rank.js'
import Clarifai from 'clarifai';
import FaceRecognition from './Component/Face/FaceRecognition.js';
import FaceComparison from './Component/Comparison/FaceComparison.js';
const app = new Clarifai.App({
apiKey: 'MYSUPERSECRETKEY'
});
const initialState = {
input: "",
imageUrl: "",
results: [],
route: "SignIn",
user: {
id: "",
name: "",
email: "",
entries: 0,
joined: "",
},
};
const particleOptions = {
particles: {
number: {
value: 40,
density: {
enable: true,
value_area: 800,
},
}
}
}
class App extends Component{
constructor() {
super();
this.state = initialState;
}
transformResponse = (response) => {
const clarifaiResults = response.outputs[0].data.regions[0].data.concepts[0].name;
const results = clarifaiResults.map((ingredient) => ({
ingredients: ingredient.name,
probablitiy: ingredient.value,
}));
this.setState({results: results.celebrityName});
return {results: []};
};
onInputChange = (event) => {
this.setState({input: event.target.value});
}
onSubmit = () => {
this.setState({imageUrl: this.state.input});
app.models
.predict(
Clarifai.CELEBRITY_MODEL,
this.state.input)
.then(response => {
console.log(response.outputs[0].data.regions[0].data.concepts[0].name)
if (response) {
fetch ('http://loclhost:3000', {
method: 'post',
headers: {'Conent-Type' : 'application/json'},
body: JSON.stringify({
input: this.state.user.input
})
})
.then((response) => response.json())
.then(count => {
this.setState(Object.assign(this.state.user, {entries:count}))
})
}
this.transformResponse(response);
})
.catch(err => console.log(err));
};
;
onRouteChange = (route) => {
if (route === 'signout'){
this.setState({isSignedIn: false})
} else if (route ==='home'){
this.setState({isSignedIn: true})
}
this.setState({route: route});
}
render() {
let { isSignedIn, imageUrl, route, results} = this.state;
return (
<div className="App">
<Particles className='particles'
params={particleOptions}
/>
<Navigation isSignedIn={isSignedIn} onRouteChange={this.onRouteChange}/>
{ route ==='home'
? <div>
<Logo />
<Rank
results = {results}/>
<ImageLinkForm
onInputChange={this.onInputChange}
onSubmit={this.onSubmit}
/>
<FaceRecognition
imageUrl={imageUrl}
/>
<FaceComparison
results = {results}
/>
</div>
: (
route === 'SignIn'
? <SignIn onRouteChange={this.onRouteChange}/>
: <Register />
)
}
</div>
);
};
}
export default App;
Rank.js
import React from 'react';
const Rank = ({results}) => {
const prediction = results.map((result) => {
const {ingredients} = result;
return (
<div>
<li className="celebrityName">{ingredients}</li>
</div>
);
});
if (prediction && prediction.length>1) {
return (
<div>
<div className='white f3'>
You look a lot like...
</div>
<div className='white f1'>
{results}
</div>
</div>
);
} else {
return (
<div>
</div>
)
}
};
export default Rank;
sorry i'm new to React. I'm trying to make a basic social network to learn react.
Context:
When i click on the "like" button, the setState should call the function to update the state of my component, but it is updated only when i refresh the page. I think the ComponentDidUpdate function isn't called like it should. What did i do wrong? Thanks for your help!
Here are the parts of the code :
Like button component:
class Like_Button extends React.Component {
constructor(props) {
super(props);
this.state = {liked : "Like"};
}
isliked(){
fetch("likes_of_user/")
.then(res => res.json())
.then((result) => {
result.map(x => {if(this.props.pk == x.liked_post){this.setState({liked: "Unlike"});}});
})
}
componentDidMount() {
this.isliked();
}
componentDidUpdate(prevProps, prevState) {
if (prevState.liked !== this.state.liked) {
this.isliked();
}
}
render() {
return (
<button className = "buttons" onClick={() => {
var csrftoken = getCookie('csrftoken');
fetch(`like_post/${this.props.pk}`, {method: "POST", headers: {'Accept': 'application/json', 'Content-Type': 'application/json','X-CSRFToken': csrftoken}})
}}>{this.state.liked}</button>
)
}
}
Newsfeed component:
class Newsfeed_comp extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch("get_newsfeed/")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{items.map((item ,index) => (
<li className="postbox" key={`${item}${index}`}>
{item.author}
{item.date}
{item.content}
<Like_Button pk={item.id} />
</li>
))}
</ul>
);
}
}
}
ReactDom render:
ReactDOM.render(<Newsfeed_comp />, document.getElementById("newsfeed_view"))
Try something like this:
LikeButton.js
import React, { useEffect, useState } from 'react';
export default function LikeButton({ pk }) {
const [like, setLike] = useState(false);
useEffect(() => {
const fetchLike = async () => {
const res = await fetch("likes_of_user/");
const result = await res.json();
if (result.length > 0) {
setLike(result.find(item => item.liked_post === pk));
}
};
try {
fetchLike();
} catch (error) {
// handle error
}
});
const handleClick = async () => {
const csrftoken = getCookie('csrftoken');
return fetch(`like_post/${pk}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken
},
method: 'POST',
});
};
return (
<button className='buttons' onClick={handleClick}>
{like}
</button>
);
};
NewsFeed.js
import React, { useEffect, useState } from 'react';
export function NewsFeed() {
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
useEffect(() => {
const getNewsFeed = async () => {
const res = await fetch('get_newsfeed/');
const result = await res.json();
setIsLoaded(true);
setItems(result);
};
try {
getNewsFeed();
} catch (error) {
setIsLoaded(true);
setError(error);
}
});
if (error) return <div>Error: {error.message}</div>;
if (isLoaded) return <div>Loading...</div>;
const list = items.map((item) => (
<li className='postbox' key={item.content}>
{item.author}
{item.date}
{item.content}
<LikeButton pk={item.id} />
</li>
));
return <ul>{list}</ul>;
};
App.js
ReactDOM.render(<NewsFeed />, document.getElementById('newsfeed_view'));
Looks like you've reversed your logic, i.e. your button directly updates the data in the backend but does nothing to update component state, so the componentDidUpdate isn't called as you've seen. The refresh is required so the component is remounted and the componentDidMount can fetch the likes data.
Try instead to update local state first, then use componentDidUpdate to issue the side-effect of updating the backend.
constructor(props) {
super(props);
this.state = { liked: true };
}
isliked() {
fetch("likes_of_user/")
.then(res => res.json())
.then((result) => {
result.map(x => {
if (this.props.pk === x.liked_post) {
this.setState({ liked: false });
}
});
})
}
componentDidUpdate(prevProps, prevState) {
if (prevState.liked !== this.state.liked) {
const csrftoken = getCookie('csrftoken');
fetch(
`like_post/${this.props.pk}`,
{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
}
);
}
}
<button
className="buttons"
onClick={() => this.setState(
prevState => ({ liked: !prevState.liked })
)}
>
{this.state.liked ? "Liked" : "Unliked"}
</button>
I need to create a Card that is dynamically created by populating data from an API. I am able to get this data but I am unable to show the view in the render method.
Kindly assist me to fix my code.
Below is my class Component where I use axios to get a form data, then I iterate through to get the key and value and assign it to the card i want to display. Now I cannot seem to see the Card at all.
class Cards extends Component {
constructor(props) {
super(props);
this.state = { users: [] }
}
componentDidMount() {
let formData = new FormData();
const username = localStorage.getItem("username");
formData.append("username", username);
const config = {
headers: { "content-type": "multipart/form-data" },
};
axios
.post("http://", formData, config)
.then((response) => {
let rows = []
let count = 0
for (var i = 0; i < response.data.length; i++) {
console.log("data: "+response.data[i].key);
rows.push(<div className="col-md-4">
<div className="card">
<p>Data {count++}</p>
<h1>{response.data[i].key}</h1>
<p>{response.data[i].value}</p>
</div>
</div>
)
this.setState({ users: rows })
}
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<div className="cards">
{this.users}
</div>
);
}
}
export default Cards;
It's not a good practice to add HTML tags into the state Instead, add your API response to the state and use the render() to render the data in proper HTML tags.
class Cards extends Component {
constructor(props) {
super(props);
this.state = {
response: {},
};
}
const apiCall = () => {
let formData = new FormData();
const username = localStorage.getItem("username");
formData.append("username", username);
const config = {
headers: { "content-type": "multipart/form-data" },
};
axios
.post("http://", formData, config)
.then((response) => {
this.setState({ response: response });
}).catch((error) => {
console.err(error);
});
}
componentDidMount() {
apiCall();
}
render() {
const { response } = this.state;
return (
<div className="cards">
{response.data.map((item, index) => {
<div key={`user-${index}`} className="col-md-4">
<div className="card">
<p>Data {index+1}</p>
<h1>{item.key}</h1>
<p>{item.value}</p>
</div>
</div>
})}
</div>
);
}
}
export default Cards;
class Cards extends Component {
constructor(props) {
super(props);
this.state = { users: [] };
}
componentDidMount() {
let formData = new FormData();
const username = localStorage.getItem("username");
formData.append("username", username);
const config = {
headers: { "content-type": "multipart/form-data" },
};
axios
.post("http://", formData, config)
.then((response) => {
this.setState({ users: response.data });
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<div className="cards">
{this.state.users?.map((user, id) => (
<div className="col-md-4" key={user.key}>
<div className="card">
<p>Data {id}</p>
<h1>{user.key}</h1>
<p>{user.value}</p>
</div>
</div>
)}
</div>
);
}
}
export default Cards;
I trying to make a pagination with a response from an API request made with ReactJs. I have one Main.js page that send props to child component which is PageButtons.js. Everything is passing well, I checked that by console logging this.props of the values I passed.
The thing is I need to update the state of props and I need that to get updated on parent component, which is Main.js. I'm using this to increment the value of limit and offset of the fetch API request, depending on the button I just clicked, but that does not happen... :(
This question as little bit more details, like the array of the fetch response (Client-side pagination of API fetch only with ReactJs).
I'll leave here Main.js code (no imports included):
export class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
token: {},
isLoaded: false,
models: [],
offset: offset,
limit: limit
};
}
componentDidMount() {
/* here is other two fetches that ask for a token */
fetch(url + '/couch-model/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'JWT ' + (JSON.parse(localStorage.getItem('token')).token)
}
}).then(res => {
if (res.ok) {
return res.json();
} else {
throw Error(res.statusText);
}
}).then(json => {
this.setState({
models: json.results
}, () => {});
})
}
render() {
const { isLoaded, models } = this.state;
if (!isLoaded) {
return (
<div id="LoadText">
Estamos a preparar o seu sofá!
</div>
)
} else {
return (
<div>
{models.map(model =>
<a href={"/sofa?id=" + model.id} key={model.id}>
<div className="Parcelas">
<img src={model.image} className="ParcImage" alt="sofa" />
<h1>Sofá {model.name}</h1>
<p className="Features">{model.brand.name}</p>
<button className="Botao">
<p className="MostraDepois">Ver Detalhes</p>
<span>+</span>
</button>
<img src="../../img/points.svg" className="Decoration" alt="points" />
</div>
</a>
)}
<PageButtons limit={limit} offset={offset}/>
</div>
)
}
}
}
And now PageButtons.js code:
export class PageButtons extends React.Component {
ButtonOne = () => {
let limit = 9;
let offset = 0;
this.setState({
limit: limit,
offset: offset
});
};
ButtonTwo = () => {
this.setState({
limit: this.props.limit + 9,
offset: this.props.offset + 9
});
};
render() {
console.log('props: ', this.props.limit + ', ' + this.props.offset);
return (
<div id="PageButtons">
<button onClick={this.ButtonOne}>1</button>
<button onClick={this.ButtonTwo}>2</button>
<button>3</button>
<button>></button>
</div>
)
}
}
Add below methods to Main.js
fetchRecords = (limit, offset) => {
// fetch call code goes here and update your state of data here
}
handleFirstButton = (limit, offset) => {
this.setState({limit : limit, offset: offset})
this.fetchRecords(limit, offset)
}
handleSecondButton = (limit, offset) => {
this.setState({limit: limit, offset : offset})
this.fetchRecords(limit, offset)
}
Main.js render method changes :
<PageButtons
limit={limit}
offset={offset}
handleFirstButton={this.handleFirstButton}
handleSecondButton={this.handleSecondButton}/>
PageButtons.js changes.
ButtonOne = () => {
let limit = 9;
let offset = 0;
this.props.handleFirstButton(limit, offset);
};
ButtonTwo = () => {
let {limit, offset} = this.props;
limit += 9;
offset += 9;
this.props.handleSecondButton(limit, offset);
};