I'm trying to figure out how to code my current API call so that I can access each field from the API call and render it, then be able to use it across multiple components. I'm using the QuickBase API call that only allows POST to pull field values. I've been out of the game for a couple of years and can't figure out how to accurately render these to be able to be used in other components by importing the api.js file. The project is a React within Electron to pull QuickBase data, and be able to create Line Charts (7 on one page) to show a job cost/hours and the jobs included departments cost/hours. All of my data is in quickbase, I just can't figure out how to get it over to react and able to actually use it!
Here is my API call:
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
}
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],"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(res => {
if (res.ok) {
return res.json().then(res => console.log(res));
}
return res.json().then(resBody => Promise.reject({status: res.status, ...resBody}));
})
.catch(err => console.log(err))
Any help would be greatly appreciated as I've been struggling on this for awhile! Right now I'm able to get all the correct data in the Console. But don't know how to go about rendering it on my application for actual use.
Thanks!
I think you should put your code inside a function and call that function from the component where you need the data, something like
import React, { Component } from 'react'
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class App extends Component {
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],"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 => {
if (response.ok) {
return response.json().then(res => {
this.setState({
data: res,
})
});
}
return response.json().then(resBody => Promise.reject({status: response.status, ...resBody}));
}).catch(err => console.log(err))
}
render() {
const { data } = this.state;
if (data === null) return 'Loading...';
return (
<div>
{/* Do something with data */}
</div>
);
}
}
export default App;
Check the Docs, you can send the JSON in the props of the component to render it.
You can modify your code following this example.
sandbox
import { useEffect, useState } from "react";
async function apiCall() {
return await new Promise((resolve, reject) => {
// Api Call
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => resolve(json));
});
}
const TestApp = () => {
let [data, setData] = useState({ Text: "Before api call." });
useEffect(() => {
(async () => {
let res = await apiCall();
res.Text = "After api call.";
setData(res);
})();
}, []);
return (
<div>
UserId: {data.userId} id: {data.id} title: {data.title}{" "}
completed: {data.completed}
</div>
);
};
module.exports = TestApp;
I have a Users class where I want to get data from the server for later writing it to state and passing data from state to the child component
export default class Users extends Component {
constructor(props) {
super(props);
this.state = {
users: this.getUsers(),
};
}
getUsers = async () => {
await return fetch(`http://localhost:3001/users`, {
method: 'POST',
accept: 'application/json'
}).then(res => {
if(res.ok) {
res.json();
}
})
}
}
this is what the console shows me when I output data about this.state.users
I tried to look for similar situations, but I didn't find anything worthwhile, so I ask for help here. I would be grateful for any advice or help. I'm only learning asynchrony in js
if you use async await, you don't have to pass callback function, just await the promises and update the state incase of successful response.
getUsers = async () => {
try {
const response = await fetch(`http://localhost:3001/users`, {
method: 'POST',
accept: 'application/json'
});
const users = await response.json();
this.setState({ users });
} catch (error) {
console.log(error);
}
}
and instead of calling getUsers function from the constructor, use componentDidMount
componentDidMount() {
this.getUsers();
}
and your state should be initially null or an empty array
this.state = {
users: []
};
Add componentDidMount and call getUsers and set state.
this.state = {
users: [],
};
getUsers = async () => {
return await fetch(`http://localhost:3001/users`, {
method: 'POST',
accept: 'application/json'
}).then(response => response.json())
.then(res => { this.seState({ users: res })})
.catch(e => { console.log(e)})
}
componentDidMount = () => {
this.getUsers()
.catch(e => console.log(e)
}
I'm trying to make a project in which the user can select a singer in a input box and the some of their music previews are displayed on the screen. It's just a prototype, and I'll improve it later. But I noticed that when I call the API(in this case I'm using the Deezer API), I'm having a hard time trying to discover how to change the query 'q' (which is the param that holds the singer). Here's the code:
import React from "react";
class MusicList extends React.Component {
constructor() {
super();
this.state = {
data: [],
selectedArtist: ''
}
this.handleChange = this.handleChange.bind(this)
}
componentDidMount() {
fetch("https://deezerdevs-deezer.p.rapidapi.com/search?q=eminem", {
method: "GET",
headers: {
"x-rapidapi-host": "deezerdevs-deezer.p.rapidapi.com",
"x-rapidapi-key": "20438f9eb4mshb2a68ca50196b46p1d55a5jsn2dbdc2b012cd"
}
})
.then(response => {
return response.json();
})
.then(response => {
this.setState({
data: response.data
})
});
}
handleChange(e) {
this.setState({
selectedArtist: e.target.value
})
}
render() {
return (
<div>
<form>
<input
type="text"
placeholder="Search..."
value={this.state.selectedArtist}
onChange={this.handleChange}
/>
<button>Search</button>
</form>
</div>
);
}
}
export default MusicList;
you need to separate the fetch part of your code as a separate function at first step; like below:
function getSingerList(query) {
fetch(`https://deezerdevs-deezer.p.rapidapi.com/search?q=${query}`, {
method: "GET",
headers: {
"x-rapidapi-host": "deezerdevs-deezer.p.rapidapi.com",
"x-rapidapi-key": "20438f9eb4mshb2a68ca50196b46p1d55a5jsn2dbdc2b012cd"
}
})
.then(response => {
return response.json();
})
.then(response => {
this.setState({
data: response.data
})
});
}
then create an input and keep track of input value by useState, check this simple tutorial from docs, then fetch the data by calling the function with query parameter when you need in submit of your search input field you've created!
handleSubmitSearch = e => {
e.preventDefault();
getSingerList(this.state.query)
}
First, you need to pass the query (aka the artist name) to the function that calls Deezer API, so create a function that only retrieve the results from freezer:
fetchArtist (name) {
fetch(`https://deezerdevs-deezer.p.rapidapi.com/search?q=${name}`, {
method: "GET",
headers: {
"x-rapidapi-host": "deezerdevs-deezer.p.rapidapi.com",
"x-rapidapi-key": "20438f9eb4mshb2a68ca50196b46p1d55a5jsn2dbdc2b012cd"
}
})
.then(response => response.json())
.then(response => {
this.setState({
data: response.data
})
});
}
Second you need to edit your componentDidMount to call the newly created function:
componentDidMount() {
this.fetchArtist('eminem')
}
Then if you want to search for an artist when the user types something, then in your handleChange do this:
handleChange(e) {
const artistName = e.target.value
this.setState({
selectedArtist: artistName
})
this.fetchArtist(artistName)
}
If you want to make the search ONLY when you click search, then you need to add an OnSubmit to your form:
<form onSubmit={this.handleSubmit} >
And then create another function called handleSubmit and move the fetchArtist call inside it
Working example:
https://jsfiddle.net/Sletheren/shgx4bwk/7/
I am currently factoring my code so as not to repeat the same lines x times, so I created a Functions.js file which I use to call functions from other classes. The problem is, that I cannot execute the function while keeping the properties of this to carry out setState, redirects etc. Here is an example, it will be more telling:
Class in functions.js :
export class KoHttpRequest extends React.Component {
constructor(props) {
super(props);
this.postRequest = this.postRequest.bind(this);
}
postRequest = async(url, json, accessToken) => {
this.setState({loaded: false, validatingAction: false});
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization' : 'Bearer '.concat(accessToken)
},
body: json
}).then((response) => {
if (response.ok === true) {
this.fetchData().then(() => {
this.setState({loaded: true}, () => {
this.userIsValidatingAnAction();
setTimeout(() => {this.setState({validatingAction: false})}, 1000);
});
})
} else {
let error = JSON.stringify(response.headers.map);
this.props.navigation.navigate('Accueil', {failedAction: true, errorReason: error.split('"error-reason":').pop().split('}},')[0].concat(' URL : '.concat(response.url))});
}
})
.catch((error) =>{
console.error(error);
});
}
render() {
return null;
}
}
And in the file where I want to call it :
import { KoHttpRequest } from '../Components&Functions/Koust.js';
createNewInvoice = () => {
new KoHttpRequest().postRequest('https://koupp.com/apex/rest/mobile/facture', JSON.stringify({
type:'C',
numero:this.state.invoiceNumber,
date_liv:this.state.pickedDate,
provider_id:this.state.selectedProvider
}), this.state.accessToken);
};
So, to explain clearly, in the class, the .then() and .error() are same for all request I do in my app, that's why I need the code here and not in the class that is calling it.
Unfortunely, I don't understand how I can tell the function that the 'this' referenced to use is in the other component. Cause actually the function is using themselve props..
Thanks for help.
I'm just trying to access the setState of class that is calling it.
In Functions.js, when it's using setState, I want it set the state of the other class actually
EDIT :
I think I found a solution using a callback.
createNewInvoice = () => {
this.setState({loaded: false, validatingAction: false}, () => {
new KoHttpRequest().koPostRequest('https://koupp.com/apex/rest/mobile/facture', JSON.stringify({
type:'C',
numero:this.state.invoiceNumber,
date_liv:this.state.pickedDate,
provider_id:this.state.selectedProvider
}), this.state.accessToken, this.props, function(result) {
if (result.status === 200) {
this.fetchData().then(() => {
this.setState({loaded: true}, () => {
this.userIsValidatingAnAction();
setTimeout(() => {this.setState({validatingAction: false})}, 1000);
});
})
}
});
});
};
But now, that's the callback function that can't access "this".
EDIT_2:
Find it. Just need to replace function() {..} by () => {..}
Thanks!
I have a REACT component:
import React from 'react';
import Weather from '../service/weatherAPI.js';
export default class DisplayWeather extends React.Component {
constructor(props){
super(props);
this.state = {
weatherData: []
}
this.getWeatherData = this.getWeatherData.bind(this);
}
componentDidMount(){
this.getWeatherData();
}
async getWeatherData(){
let data = await Weather(this.props.location)
this.setState({ weatherData: data});
console.log(this.state.weatherData)
}
This function references a function exported from another file which is using fetch to call an endpoint. All the data returns correctly from the endpoint I am calling. However, when trying to set this data onto the state, my data is undefined.
Below is my API call, just in case I have missed anything here:
const Weather = (location) => {
fetch(url, {
Method: 'GET',
headers : {
'Accept': 'application/json'
},
})
.then((raw) => raw.json())
.then((response) => {
return response
})
}
export default Weather;
Thanks in advance.
You need to return the promise like this in your weather function:
const Weather = (location) => {
return fetch(url, {
Method: 'GET',
headers : {
'Accept': 'application/json'
},
})
.then((raw) => raw.json())
.then((response) => {
return response
})
}
That way the await is working on the promise instead of just the function.