Fetch API request to my React app - javascript

I'm trying to call an API to show information on my website in React.js, the API needs a token to be read, but I don't know what I have to do to generate the token, since my application doesn't need any register or login. It's like a catalog of products and you can personalize them. I don't understand very well this because I'm new and I'm learning all by myself, so I'm sorry if this is confusing, feel free to ask anything, I'll try to answer :)
Here's the code I have until now:
export class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
models: [],
isLoaded: false
};
}
componentDidMount() {
fetch(myUrlAPI)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
models: json
});
});
}
render() {
const { isLoaded, models } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
<ul>{models.map(model => <li>{model.name}</li>)};</ul>
<a href="/sofa">
<div className="Parcelas">
<img
src="../../img/image-card-1#2x.png"
className="ParcImage"
alt="sofa"
/>
<h1>Sofa hipnos</h1>
<h2>
1,200<span>€</span>
</h2>
<p className="Features">
w 20.5 x 15.5 x h 19.5 (cm)<br />Pele
</p>
<button className="Botao">
<p className="MostraDepois">See Details</p>
<span>+</span>
</button>
<img
src="../../img/points.svg"
className="Decoration"
alt="points"
/>
</div>
</a>
</div>
);
}
}
}
In the <ul> tag I was just trying to test the results from the json.
Also, everytime I use .map to make an array, I get this error (TypeError: models.map is not a function) or similar, can you tell me why?

Try this way and for token you need to confirm with the backend developer as how and what you should send.
let token = '1234567';
fetch(myUrlAPI, {
method: "GET",
headers: {
"authorization-key": token
}
}).then(res => res.json()
).then(function(json) {
this.setState({
isLoaded: true,
models: json
});
}, function(error) {
console.log(error)
})

Related

how I improve the asynchrony in this javascript code?

i have the next code in react, it requests information by api in monday.com, then with the answer I make another request for the weather by cities. then I render a climate card for each city found. the problem is that the array "cityWeathers" should have 9 elements, but some calls come 3, in another 5, in another 7, always several. I don't know what the error can be.
constructor(props) {
super(props);
this.state = {
setData: {},
context:{},
settings: {},
myData: { boards: [] },
cityWeathers:[]
};
}
componentDidMount() {
const getWeather = async () => monday.api('query { boards( ids : xxxxxxxxxx ) { items { id : name column_values { text }}}}')
.then((res) => {
this.setState({myData:res.data});
this.state.myData.boards.map((board) => {
board.items.map((item) =>{
fetch(`https://api.weatherapi.com/v1/current.json?key=xxxxxxxxxxxxxxxxxxxxxx=${item.column_values[3].text}&aqi=no`)
.then((res) => res.json())
.then((json) => {
//console.log(json);
let cityWeather ={
name: json.location.name,
temp_c:json.current.temp_c,
temp_f:json.current.temp_f,
condition: json.current.condition.text,
localTime: json.location.localtime,
icon: json.current.condition.icon
};
let cityWeathers = [...this.state.cityWeathers, cityWeather];
this.setState({cityWeathers});
})
})}
)
}
)
getWeather()
}
render(){
return(
<div className="App">
<div className="container">
<div className="row">
<div className="col-md-4">
{console.log(this.state.cityWeathers.length)}
{ this.state.cityWeathers.map((city) =>
<WeatherCard key={city.name} className="cards" name={city.name}
temp_c={city.temp_c} temp_f={city.temp_f} icon={city.icon}
condition={city.condition} localtime={city.localTime} />)
}
</div>
</div>
</div>
</div>
)
}
}
>I request information by api in monday.com, then with the answer I make another request for the weather by cities. then I render a climate card for each city found. the problem is that the array "cityWeathers" should have 9 elements, but some calls come 3, in another 5, in another 7, always several. I don't know what the error can be.

How to declare json data fields that I am getting in an api in ReactJs

As can be seen from the image, I am getting error lines under element.url etc. from line no. 62. I am fetching data from news api and in result I am getting json response which looks like this. I am passing these title, description etc. from api response to another component in my react app as props.
Now the error says this :
any |
Property 'title' does not exist on type 'never'.ts(2339)
So my question is; is there a way I can declare the rest of the fields of the json data so my editor doesn't give this error? Here is my code....
constructor(props) {
super(props);
this.state = {
articles: [],
totalResults: 0,
loading: false,
page: 1,
};
}
async componentDidMount() {
let apiKey = `https://newsapi.org/v2/top-headlines?country=in&apiKey=7e87c89bfbbd4b8b8bb0721d45a6d454&pageSize=18&page=${this.state.page}`;
let data = await (await fetch(apiKey)).json();
this.setState({ articles: data.articles, totalResults: data.totalResults });
}
render() {
return (
<div className="container my-4">
<h2 id="heading">Top headlines of the day</h2>
<div className="row my-4">
{this.state.articles.map((element) => {
return (
<div className="col-md-4 mb-3" key={element.url}>
<NewsItem
title={element.title}
description={element.description}
imageUrl={element.urlToImage}
more={element.url}
/>
</div>
);
})}
</div>

ReactJS: How to update a boolean field in an API using a POST request

So what I am basically doing is, I have an API of call activities and its own details.
I have to archive a call and in that API of calls, each call has a field called "is_archived"
I need to be able to update the API using a click of a button to archive a call. (So basically change the field of "is_archived" from "false" to "true" once the button is clicked)
And once that call has been archived, it shouldnt render nor be displayed on the application anymore.
I'm getting a "Failed to load resource: the server responded with a status of 400 (Bad Request)" with my code and I'm sure I'm doing something wrong, I just cant spot it.
Thank you!
Here is my code so far:
App.jsx
import React, { Component} from 'react';
import { ActivityFeed } from './components/activity-feed/activity-feed.component.jsx';
import Header from './Header.jsx';
class App extends Component {
constructor() {
super();
this.state = {
calls: [],
showMessage: false,
is_archived: false
};
}
componentDidMount() {
fetch('https://aircall-job.herokuapp.com/activities')
.then(response => response.json())
.then(activities => this.setState({ calls: activities }))
document.getElementById("reset").disabled = true;
}
handleArchive = event => {
this.setState({calls: []});
this.setState({ showMessage: true });
document.getElementById("archive").disabled = true;
document.getElementById("reset").disabled = false;
};
handleReset = event => {
this.componentDidMount();
this.setState({ showMessage: false });
document.getElementById("reset").disabled = true;
document.getElementById("archive").disabled = false;
};
render() {
const { calls, showMessage } = this.state;
console.log(calls);
return (
<div className='App'>
<Header/>
<ActivityFeed calls={calls} />
<button type="button" className="archive-btn" id="archive"
onClick={this.handleArchive}>Archive All Calls</button>
{showMessage && <p>All calls have been archived</p>}
<button type="button" className="reset-btn" id="reset"
onClick={this.handleReset}>Reset Archived Calls</button>
</div>
);
};
}
export default App;
Activity.component.jsx
import React from 'react';
import './activity-detail.styles.css';
import missed from '../../resources/images/missed.svg';
import answered from '../../resources/images/answered.svg';
import voicemail from '../../resources/images/voicemail.svg';
function formatDate(date) {
var localDate = new Date(date);
return localDate.toDateString().split(' ').slice(1).join(' ');
}
function formatTime(time) {
var localTime = new Date(time);
return localTime.toLocaleTimeString().replace(/(.*)\D\d+/, '$1');;
}
function callType(type) {
if (type === "missed") {
return <img src={missed} alt="missed" className="call-icon"/>
}
else if (type === "answered") {
return <img src= {answered} alt="answered" className="call-icon"/>
}
else
return <img src= {voicemail} alt="voicemail" className="call-icon"/>
}
function archiveCall(id) {
fetch(`https://aircall-job.herokuapp.com/activities/${id}`, {
mode: 'no-cors',
method: "POST",
headers: {
'Accept' : 'application/json',
"Content-Type": "application/json"
},
body: JSON.stringify({
is_archived: true
}),
})
}
export const Activity = props => (
<div className='activity-container'>
<p> Date {formatDate(props.call.created_at)} </p>
<p> Time {formatTime(props.call.created_at)} </p>
<p> From {props.call.from} </p>
<p> To {props.call.to} </p>
<p> Via {props.call.via} </p>
<p> Call type {callType(props.call.call_type)} </p>
<button type="button" className="archive-call" id="archive-call"
onClick={archiveCall(props.call.id)}
>Archive call</button>
</div>
);
ActivityFeed.component.jsx
import React from 'react';
import { Activity } from '../activity-detail/activity-detail.component';
import './activity-feed.styles.css';
export const ActivityFeed = props => (
<div className='activity-feed'>
{props.calls.map(calls => (
<Activity key={calls.id} call={calls}/>
))}
</div>
);
For some reason, I'm not sure why, but if you have no-cors mode set on your fetch POST request, the content-type on your request gets changed to text/plain.
Fetch API - Content-Type is sent as text/plain when it's set to application/json
I was able to figure this out by duplicating your request in a sandbox, right-clicking your request in Chrome's network tab, and choosing "Copy as cURL". Then import it into Postman so I could replicate the exact request. There I could see it was converted into a plain-text content instead of a JSON body as intended.
Of course you can also see these things in the requests inside the network tab, but sometimes putting it inside Postman makes it stand out more clearly.
So the solution is to simply omit the "no-cors" option and your request works fine in React.
fetch(`https://aircall-job.herokuapp.com/activities/${id}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
is_archived: true
})
});
https://codesandbox.io/s/cranky-khayyam-qm2rz?file=/src/App.js

Converting to send API Data to other components to be used in Line Charts

I'm trying to see how I can set this data to props or what I need to do to be able to use this data in my individual Line Chart components using Chart.js. The Api Call is working and I'm getting all the data I need on 2 separate Api.js files and am able to get this to render. However now that I have that, i'm wondering what my best option is for sending this over to be able to be displayed in the line charts. I'm also getting errors that Each Child in a list should have a key prop which is where you see me attempting to assign keys. I'm inexperienced with this so any help and direction would be appreciated.
Here is an api call getting data I'm trying to share across components:
import React, { Component } from 'react'
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXX_XXXX_XXXXXXXXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class JobsTableApi 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...';
return (
<ul>
{Object.keys(data["data"]).map(item =>
<div>
<h2>
{data["data"][item][3].value} -- {data["data"][item][6].value}
<br />
<a>{data["data"][item][40].value}</a>
</h2>
<h5>Overall Project Totals:</h5>
<p key="AdjContractAmt">Adj Contract Amount: ${Math.round(data["data"][item][80].value)},</p>
<p key="DesignHours">Design Hours: {Math.round(data["data"][item][88].value)},</p>
<p key="DesignAmount">Design Amount: ${Math.round(data["data"][item][91].value)},</p>
<p key="SubRoughHours">SubRough Hours: {Math.round(data["data"][item][92].value)},</p>
<p key="SubRoughAmount">SubRough Amount: ${Math.round(data["data"][item][95].value)},</p>
<p key="RoughHours">Rough Hours: {Math.round(data["data"][item][96].value)},</p>
<p key="RoughAmount">Rough Amount: ${Math.round(data["data"][item][98].value)},</p>
<p key="FinishHours">Finish Hours: {Math.round(data["data"][item][104].value)},</p>
<p key="FinishAmount">Finish Amount: ${Math.round(data["data"][item][107].value)},</p>
<p key="CloseHours">Close Hours: {Math.round(data["data"][item][477].value)},</p>
<p key="CloseAmount">Close Amount: ${Math.round(data["data"][item][480].value)},</p>
<p key="CurrentHours">CURRENT/ACTUAL Hours: {Math.round(data["data"][item][479].value)},</p>
<p key="CurrentAmount">CURRENT/ACTUAL Amount: ${Math.round(data["data"][item][224].value)}</p>
</div>
)}
</ul>
)
}
}
export default JobsTableApi;
I've heard that redux is good for this? But i've also heard that is mainly for larger applications, once I get this data to be used in the line charts thats about all I'd need.
File structure:
>src
>components
>charts
>multipleLineCharts.js
>API
>api.js1
>api.js2
Thanks!
that is about identity of divs inside structure:
https://reactjs.org/docs/lists-and-keys.html
When You mapping the array of elements then:
{Object.keys(data["data"]).map(item, i =>
<div key = {i}>
</div>
}
For displaying charts i suggest to use
https://recharts.org/

Accessing JSON from public folder in ReactApp

I have a a JSON file which I would like to use its content into my React App.
This is an excerpt from my code
export default class App extends Component{
constructor(props){
super(props);
this.state = {
entry : []
}
}
componentDidMount(){
fetch(process.env.PUBLIC_URL + `./js/data.json`)
.then(res => res.json())
.then(json => this.setState({ entry: json }));
}
render(){
return(
<div>
<ul>
{this.state.entry.map( x => (
<li>
<div className='centering'>
<span>
<img alt='' key={x.img} src={process.env.PUBLIC_URL + `./img/${x.img}.jpg`}/>
</span>
<span className='txt'>
{ x.date }
</span>
<span>
<p>{ x.ctx }</p>
</span>
</div>
<div className='hr-line'></div>
</li>
))}
</ul>
</div>
)
}
}
this is the content of my data.json
{
"entry" : {
"2" : [
{
"date":"1/1/1",
"img":"profile",
"ctx":"as"
}
],
"1" : [
{
"date":"1/1/1",
"img":"profile",
"ctx":"as"
}
]
}
When I save the file, on the browser it shows TypeError: this.state is null
onrender {this.state.entry.map (x => ...
Is there something missing, or it is impossible to do so?
Thank you in advance.
Rendering is done before componentDidmount. You need to wait for your data to load before to do your map. Something like :
export default class App extends Component{
constructor(props){
super(props);
this.state = {
entry : [],
anyData: false
}
}
componentDidMount(){
fetch(process.env.PUBLIC_URL + `./js/data.json`)
.then(res => res.json())
.then(json => this.setState( prevState => ({ ...prevState, entry: json, anyData: true })));
}
render(){
if(!anyData) {
return <Loader />
}
return(
<div>
<ul>
{this.state.entry.map( x => (...))}
</ul>
</div>
)
}
}
There is also a possibility to use async lifecycle method :
async componentDidMount() {
const res = await fetch(...);
const json = await res.json();
this.setState( prevState => ({ ...prevState, entry: json, anyData: true }));
}
But it does not change the fact that it will be done after rendering.
React expects the .map for iterative rendering to work on an array of items only.
Therefore, changing the json input to return an array of items will help resolve the problem.
Existing input that does not work with .map:
"entry" : { "1" : [....], "2" : [....] } --> Input is not an array of items.
--> .map does not support this format
How to make it work with .map?
"entry" : [ {"1" : {....} , {"2" : {....} ] --> Input is an array of items.
--> .map works with this format
Additional: How to avoid 'null value' error in render method?
The render method must explicitly check for null condition before trying to render elements. This can be done as follows:
render(){
return(
<div>
<ul>
{ (this.state.entry) &&
this.state.entry.map( x => (
<li>
...
</li>
))
}
</ul>
</div>
)
}

Categories

Resources