Need help to display data from external API - javascript

I fetched some data from an API, Im trying to display the data but I'm doing something wrong. Can someone help? I have attached a photos of the fetched data on the console and my code[![data api
import React, {useState, useEffect} from 'react'
import './Track.css';
export default function Track() {
const [carbon] = useState([])
useEffect( () => {
const headers = {
'Accept':'application/json'
};
fetch('https://api.carbonintensity.org.uk/intensity',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
})
return (
<div>
<p>Track</p>
<div>
<p>{carbon.forecast}</p>
</div>
</div>
)
}
]1]1

Change to
import React, { useState, useEffect } from 'react'
import './Track.css';
export default function Track() {
const [carbon, setCarbon] = useState([])
useEffect(() => {
const headers = {
'Accept': 'application/json'
};
fetch('https://api.carbonintensity.org.uk/intensity',
{
method: 'GET',
headers: headers
})
.then(function (res) {
setCarbon(res.data)
}).then(function (body) {
console.log(body);
});
})
return (
<div>
<div>
{carbon.map((obj, i) => (
<li key={i}>
<ul>{obj.from}</ul>
</li>
))}
</div>
</div>
)
}
I recommend to you study https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map

you forgot some little thing:
first you forgot the setCarbon in the useStae hook you will need it to pass the response from the fetch.
You forgot to set the state in the fecth.
You will need to add a condition to render only when the state (carbon) is set.
you need to add an empty dependency to useEffect
import React, { useState, useEffect } from "react";
export default function Track() {
const [carbon, setCarbon] = useState([]);
useEffect(() => {
const headers = {
Accept: "application/json"
};
fetch("https://api.carbonintensity.org.uk/intensity", {
method: "GET",
headers: headers
})
.then((res) => {
return res.json();
})
.then((body) => {
console.log(body.data);
setCarbon(body.data);
});
}, []);
return (
<div>
<p>Track</p>
{carbon.length > 0 && (
<div>
{carbon.map((c, i) => (
<p key={i}>
<div>from: {c.from} </div>
<div>to: {c.to}</div>
<div>forecast: {c.intensity.forecast}</div>
<div>actual: {c.intensity.actual}</div>
<div>index: {c.intensity.index}</div>
</p>
))}
</div>
)}
</div>
);
}

Here you go,
Remember, state is like a place to store data for your component.
When you use fetch, you are getting data and now you need to save it to your state.
If you use state inside of your JSX, you can get the information to display.
Check out the console log, to look at the data structure that is returned from the fetch. This is what is set to the state "data". It can be called whatever you want. You can iterate through it, and dynamically display the data in JSX if you wanted, but I just hardcoded it for you so it's easier to understand.
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://api.carbonintensity.org.uk/intensity", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
})
.then((res) => res.json())
.then((data) => setData(data))
.catch((e) => console.error(e));
}, []);
console.log("data:", data);
return (
<div>
<p>Track</p>
<div>
<p>From: {data.data["0"].from}</p>
<p>To: {data.data["0"].to}</p>
<div>Intensity:</div>
<p>forecast: {data.data["0"].intensity.forecast}</p>
<p>forecast: {data.data["0"].intensity.actual}</p>
<p>forecast: {data.data["0"].intensity.index}</p>
</div>
</div>
);

Related

Fetch method in useEffect is in infinite loop

I was getting the infinite loop of the code getting executed, but I couldn't find where the problem was. As I am new with react I sometimes struggle to see the problem. Could it be the dependecy or that I forgot to close something off?
import {useCookies} from "react-cookie";
import React, {useEffect, useState} from "react";
import CircularProgress from "#mui/material/CircularProgress";
import {Navigate} from "react-router-dom";
const Date = () => {
const [cookies] = useCookies(['XRSF-TOKEN']);
const [loading, setloading] = useState(false);
const [error, seterror] = useState(false);
const [users, setusers] = useState([]);
useEffect(() => {
setloading(true);
fetch("/allotherusers", {credentials: "include"})
.then(response => response.text())
.then(body => {
if (body === '') {
return <Navigate to="/" />
}
else {
setusers(JSON.parse(body));
}
setloading(false);
});
}, [setusers, setloading])
const userlist = users.map(user => {
return (
<div>
<p> {user.firstname}</p>
<button onClick={() => like(user, false)}>Like</button>
</div>
)
});
const like = async (likeduser, superlike) => {
const likemodel =
{
likeduser: likeduser,
superlike: superlike
}
await fetch('/liked', {
method: 'POST',
headers: {
'X-XSRF-TOKEN': cookies['XRSF-TOKEN'],
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(likemodel),
credentials: 'include'
});
};
return (
<div>
{userlist}
</div>
);
}
export default Date;
Here you see how the frontend is keep calling the api the request.
Because both setusers, setloading is updating inside the useEffect which causes to fire the useEffect again. Just remove the side Effects from the useEffect array
}, [])
inside of your effect function, when you do setusers(JSON.parse(body)) and setloading(false) you are updating userData to a new array. Even if all the items inside of that new array are exactly the same, the reference to the new userData array has changed, causing the dependencies of the effect to differ, triggering the function again -- ad infinitum.
One simple solution is to simply remove setusers from the dependency array. In this way, the useEffect function basically acts similar to componentDidMount in that it will trigger once and only once when the component first renders.
useEffect(() => {
setloading(true);
fetch("/allotherusers", {credentials: "include"})
.then(response => response.text())
.then(body => {
if (body === '') {
return <Navigate to="/" />
}
else {
setusers(JSON.parse(body));
}
setloading(false);
});
}, [])
I think you should try this.!
yes the problem is dependency,you are using callback(setState) as dependency ,you can keep and empty dependency since on the page render the api gets called and your state gets set.
useEffect(() => {
function fetchUsers(){
setloading(true);
fetch("/allotherusers", {credentials: "include"})
.then(response => response.text())
.then(body => {
if (body === '') {
return <Navigate to="/" />
}
else {
setusers(JSON.parse(body));
}
setloading(false);
});
}
fetchUers();
}, [])

How to have conditional defaultValues from useEffect in react-select within react-hook-form?

I'm working on a form using react-hook-form that contains a react-select CreatableSelect multiselect input. The multiselect is used for tags of a given post and it is conditional based on if the user selects to update the tags of an existing post.
My issue is that the defaultValue for the multiselect is not working when a user selects an existing post that contains tags.
The overall flow is: User selects existing post (in PublicShareNetworkSelect in my example) > onChange function changes the post ID stored in hook (selectedNetwork in my example) > change in selectedNetwork fires getNetworkData function that sets the tags variable (networkTags) used as the multiselect defaultValue
Also the getTags() function is used to populate the options in the multiselect.
I believe that the issue as something to do with getting the data from the APIs because I tried to create a minimum reproducible example, but it works exactly how I want it to without the axios calls. However, when I console.log the allTags and networkTags in my full example, there are matching objects in the arrays (the matches should be the defaultValue).
Code example: Main/Parent form component
import React, { useState, useEffect } from "react";
import axios from "axios";
import Form from "react-bootstrap/Form";
import { useForm, Controller } from "react-hook-form";
import CreatableSelect from "react-select/creatable";
import Button from "react-bootstrap/Button";
import PublicShareNetworkSelect from "./publicShareNetworkSelect";
function PublicShareForm(props) {
const {
register,
handleSubmit,
reset,
control,
errors,
watch,
onChange,
} = useForm();
const [loading, setLoading] = useState(false);
const [selectedNetwork, setSelectedNetwork] = useState([]);
const [allTags, setAllTags] = useState();
const [networkTags, setNetworkTags] = useState([]);
//Create axios instance
const axiosSharedNetwork = axios.create();
async function getTags() {
const getAllTagsApi = {
url: "/public-share/get-all-tags",
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
method: "GET",
};
await axiosSharedNetwork(getAllTagsApi)
.then((response) => {
const resData = response.data;
const tags = resData.map((tag, index) => ({
key: index,
value: tag.tag_id,
label: tag.name,
}));
setAllTags(tags);
setLoading(false);
})
.catch((error) => {
console.log(error.response);
});
}
async function getNetworkData(networkId) {
const getNetworkDataApi = {
url: "/public-share/get-network/" + networkId,
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
method: "GET",
};
const getNetworkTagsApi = {
url: "/public-share/get-network-tags/" + networkId,
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
method: "GET",
};
await axiosSharedNetwork(getNetworkDataApi)
.then(async (response) => {
const resData = response.data;
//Set some variables (i.e. title, description)
await axiosSharedNetwork(getNetworkTagsApi)
.then(async (response) => {
const tagResData = response.data;
const tags = tagResData.map((tag, index) => ({
key: index,
value: tag.tag_id,
label: tag.name,
}));
setNetworkTags(tags);
setLoading(false);
})
.catch((error) => {
console.log(error.response);
});
})
.catch((error) => {
console.log(error.response);
});
}
useEffect(() => {
getTags();
getNetworkData(selectedNetwork);
reset({ tags: selectedNetwork });
}, [reset]);
async function onSubmit(data) {
//Handle submit stuff
}
console.log(allTags);
console.log(networkTags);
return (
<Form id="public-share-form" onSubmit={handleSubmit(onSubmit)}>
<Form.Group>
<Form.Label>Create New Version of Existing Shared Network?</Form.Label>
<PublicShareNetworkSelect
control={control}
onChange={onChange}
setSelectedNetwork={setSelectedNetwork}
/>
<Form.Label>Tags</Form.Label>
<Controller
name="tags"
defaultValue={networkTags}
control={control}
render={({ onChange }) => (
<CreatableSelect
isMulti
placeholder={"Select existing or create new..."}
onChange={(e) => onChange(e)}
options={allTags}
defaultValue={networkTags}
classNamePrefix="select"
/>
)}
/>
</Form.Group>
<Button variant="secondary" onClick={props.handleClose}>
Cancel
</Button>
<Button variant="primary" type="submit">
Share
</Button>
</Form>
);
}
export default PublicShareForm;
PublicShareNetworkSelect - the select component that triggers the function to set the existing post id (selectedNetwork):
import React, { useState, useEffect } from "react";
import axios from "axios";
import { Controller } from "react-hook-form";
import Select from "react-select";
function PublicShareNetworkSelect(props) {
const [loading, setLoading] = useState(false);
const [networks, setNetworks] = useState([]);
//Create axios instance
const axiosNetworks = axios.create();
// Add a request interceptor
axiosNetworks.interceptors.request.use(
function (config) {
// Do something before request is sent
setLoading(true);
return config;
},
function (error) {
// Do something with request error
setLoading(false);
return Promise.reject(error);
}
);
// Add a response interceptor
axiosNetworks.interceptors.response.use(
function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
setLoading(true);
return response;
},
function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
setLoading(false);
return Promise.reject(error);
}
);
async function getNetworks() {
const getNetworksApi = {
url: "public-share/get-user-networks/" + props.username,
method: "GET",
};
await axiosNetworks(getNetworksApi)
.then(async (response) => {
setNetworks(
response.data.map((network, index) => ({
key: index,
value: network.network_id,
label: network.title,
}))
);
setLoading(false);
})
.catch((error) => {
console.log(error.response);
});
}
useEffect(() => {
getNetworks();
}, []);
function handleChange(data) {
console.log(data);
if (data) {
props.setSelectedNetwork(data.value);
props.getNetworkData(data.value);
} else {
props.setNetworkTitle("");
props.setNetworkDesc("");
}
}
if (!loading) {
if (networks.length === 0) {
return (
<React.Fragment>
<br />
<p className="font-italic text-muted">
You haven't created any public networks yet.
</p>
</React.Fragment>
);
} else {
return (
<Controller
name="tags"
defaultValue={[]}
control={control}
render={(props) => (
<CreatableSelect
isMulti
placeholder={"Select existing or create new..."}
onChange={(e) => onChange(e)}
// defaultValue={networkTags}
options={allTags}
classNamePrefix="select"
{...props}
/>
)}
/>
);
}
} else {
return <React.Fragment>Loading...</React.Fragment>;
}
}
export default PublicShareNetworkSelect;
Edit 1: console.log output for allTags (options) and networkTags (defaultValue)
The problem is, defaultValue is cached at the first render. The same applies to defaultValues property passed to useForm.
Important: defaultValues is cached at the first render within the custom hook. If you want to reset the defaultValues, you should use the reset api.
As quote from the docs suggests - you have to use reset. I've modified your example accordingly. Take a look here. As you can see I'm asynchronously resetting the form and it works.
Also, pay attention to render prop of the Controller - I'm passing down all props given, not only onChange. It's so because there are other important thingies in here (like value). By wrapping your component in Controller you have to provide onChange and value pair at least.
If you want to read more about reset take a look here.

How can I POST data using API from REACTJS?

This is my react code here I want to POST Data using postPoll API and update polls state but I am not understand how can do that.
please help..! please help..!please help..!please help..!please help..!please help..!please help..! at line number 33, 34 ( handalchange )
import React, { useState, useEffect } from "react";
import Poll from "react-polls";
import "../../styles.css";
import { isAutheticated } from "../../auth/helper/index";
import { getPolls, postPoll } from "../helper/coreapicalls";
import axios from "axios";
import { API } from "../../backend";
const MainPoll = () => {
const userId = isAutheticated() && isAutheticated().user._id;
const [polls, setPoll] = useState([]);
const [error, seterror] = useState(false);
useEffect(() => {
loadPoll();
}, []);
const loadPoll = () => {
getPolls().then((data) => {
if (data.error) {
seterror(data.error);
} else {
setPoll(data);
console.log(data);
}
});
};
// Handling user vote
// Increments the votes count of answer when the user votes
const handalchange = async (pollId, userId, answer) => {
console.log(pollId); // getting
console.log(userId); // getting
console.log(answer); // getting
await axios.post(`${API}/vote/${pollId}`, userId, answer);
// postPoll(pollId, { userId, vote }).then(() => {
// loadPoll();
// });
};
return (
<div className="">
<div className="container my-5">
<h1 className="blog_heading my-3">Poll's of the Day</h1>
<div className="row">
{polls.reverse().map((poll, index) => (
<div className="col-lg-4 col-12 poll_border" key={index}>
<Poll
noStorage
question={poll.question}
answers={Object.keys(poll.options).map((key) => {
return {
option: key,
votes: poll.options[key].length,
};
})}
onVote={
(answer) =>
handalchange(poll._id, userId, answer, console.log(answer)) // getting vote
}
className="mb-2"
/>
</div>
))}
</div>
</div>
</div>
);
};
export default MainPoll;
this is my frontend-
POSTMAN - request = >
and here is my backend API -
// post
export const postPoll = (pollId, post) => {
return fetch(`${API}/vote/${pollId}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(post),
})
.then((response) => {
return response.json();
})
.catch((err) => console.log(err));
};
It depends on what object does onVote event from Poll component pass. But if it's vote object, that's required in postPoll method as second arguement, than:
function in onVote event should pass poll.id from this component and vote object from Vote component onVote event itself:
onVote={(vote) => handalchange(poll.id, vote)}
handalchange should fire postPoll api method with these arguements and load updated poll data on success:
const handalchange = (pollId, vote) => {
postPoll(pollId, vote).then(() => {
loadPoll();
});
}

how post props redux React

I would like to explain my problem of the day.
I can't post "this.props.total",
I do not understand how to post a props, can you help me pls?
currently the props works correctly.
import React, { Component } from 'react';
import { CardText, } from 'reactstrap';
import { connect } from 'react-redux'
class thisPropsFortotal extends Component {
handleSubmit = (e) => {
e.preventDefault();
const config = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({this.props.total}),
};
const url = entrypoint + "/alluserpls";
fetch(url, config)
.then(res => res.json())
.then(res => {
if (res.error) {
alert(res.error);
} else {
alert(`ajouté avec l'ID ${res}!`);
}
}).catch(e => {
console.error(e);
}).finally(() => this.setState({ redirect: true }));
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<button type="submit">Add</button>
</form>
<CardText>{this.props.total} € </CardText>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
total: state.addedItems.reduce((acc, item) => { return acc + (item.quantity *
item.price) }, 0)
//addedItems: state.addedItems
}
}
export default connect(mapStateToProps)(thisPropsFortotal)
Do you have an idea of how to fix this? Neff
You are attempting to stringify {this.props.total}, which is invalid syntax.
You can pass an object explicitely defining the total property like so:
body: JSON.stringify({total: this.props.total}),
Or, simply stringify the this.props object itself:
body: JSON.stringify(this.props),

React Functional Component - useState / useCallback - value changes back / reverts to initial value on submit

I have a functional component where I am submitting a text value entered by the user.
import React, { useState, useEffect, useCallback } from 'react'
// other imports
function Settings (props) {
const [primaryColor, setPrimaryColor] = useState('#E02E26');
useEffect(() => {
fetch(`//URL`, {...})
.then(res => res.json())
.then(
(result) => {
setPrimaryColor(result.primaryColor);
})
},[]);
const handlePrimaryColorChange = useCallback((newValue) => {
setPrimaryColor(newValue);
}, []);
const handlePCChange = useCallback((newValue) => {
setPrimaryColor(newValue.hex)
}, []);
const handleSubmit = useCallback((_event) => {
fetch(`//URL`, {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({
primaryColor: primaryColor
})})
.then(res => res.json())
.then((result) => {
console.log('response recieved from post api');
})
}, []);
return (
<div>
<Page title="Customise UI">
<Form onSubmit={handleSubmit}>
<TextField type="text" onChange={handlePrimaryColorChange} value={primaryColor} />
<SketchPicker disableAlpha={true} color={primaryColor} onChangeComplete={handlePCChange}/>
<Button primary submit>Save Settings</Button>
</Form>
</Page>
</div>
)
Settings.getInitialProps = async (context) => {
return context.query;
}
The data is correctly loaded by 'useEffect' and 'primaryColor' is set and the correct values are displayed on TextField and SketchPicker components.
When I change values in either TextField and SketchPicker then the value gets updated on-screen in the other component correctly.
Now, when I click on Submit, the value that is received on the backend or if I print it just before fetch is '#E02E26' (the initial value in useState). The fetch request is successful.
What is going wrong here? I want to send the current primaryColor value in the fetch body.
Try adding primaryColor to the array:
const handleSubmit = useCallback((_event) => {
fetch(`//URL`, {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({
primaryColor: primaryColor
})})
.then(res => res.json())
.then((result) => {
console.log('response recieved from post api');
})
}, [primaryColor]);

Categories

Resources