Can't Render Data with API Call - reactjs

I've been stuck on this for quite some time now, I can't use a get request and have to use post as that is the only way I am able to get field values back. And no matter what I do, I can't get ANY data to render, as of right now, all i see is the loading... telling me that the data is null. yet I don't know how to change this. Any help would be appreciated.
this is using Fetch to call the QuickBase RESTful API to get multiple field values to just use as data points on line charts. I know this shouldn't be this hard, yet nothing I do can render any data. Using React as well.
import React, { Component } from 'react'
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class JobsTableApi 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(res => res.json())
.then( res => {
this.setState({
data: [],
})
});
}
render() {
const { data } = this.state;
if (data === null) return 'Loading...';
return (
<div>
<h3>
{data}
</h3>
</div>
)
}
}
export default JobsTableApi;
some users have said to map through, but the problem is I don't know how with my current code. some say to use data.value yet it's an array. i've tried data[3], since there is no 'job name' field, or 'amount' field, it's all split up by number as shown above in my select body.
Thanks,

I guess the root cause is coming from using same names in the React's fetch and as a key in the QB response.
You can try to reach data by map via data["data"][item][6].value (6 is a field ID)
I have created and tested the following and it works properly.
<div id="mydiv"></div>
<script type="text/babel">
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class JobsTableApi extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
};
}
componentDidMount() {
this.fetchData();
}
fetchData = () => {
let body = {"from":"XXXXXXXXXXX","select":[3,6,7],"sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":6,"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 =>
<li key={item}>
<a> {data["data"][item][6].value} </a>
</li>
)}
</ul>
)
}
}
ReactDOM.render(<JobsTableApi />, document.getElementById('mydiv'))
</script>

Related

API POST using fetch helper function doesn't render update after response is received

Beginner at React (and JS)...
I am trying to update text on the screen after my API helper function has completed a call. Instead, it returns empty. I have verified with the console that the data is being received. I followed the ComponentDidMount method from other similar questions but am still having no success. My code also seems to make multiple API calls, even though my intent is to only make one; I have to wonder if the issue stems from that.
Helper function:
export function apiHelper(url, data = {}, method = 'POST') {
return fetch(url, { // Return promise
method: method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(res => res.json())
.then((result) => {
console.log(result);
return result;
}, (error) => {
error = error;
})
}
React Component that renders incorrectly after data is received:
class Headache extends React.Component {
constructor(props) {
super(props);
this.state = {
apiResponse: null,
};
}
componentDidMount() {
apiHelper(URLredacted,JSONredacted)
.then(response => {
this.setState({
apiResponse: response
});
console.log("state set.",response)
});
}
render() {
const jsonResponse = JSON.stringify(this.props.apiResponse)
return (
<div>
<img className="logoheader" src = {logo}/>
<ColoredLine color="grey"/>
<p>{jsonResponse}</p>
</div>
);
}
}
export function apiHelper(url, data = {}, method = 'POST') {
return fetch(url, { // Return promise
method: method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(res => res.json())
.catch(err=>console.log(err))
}
second page:
class Headache extends React.Component {
constructor(props) {
super(props);
this.state = {
apiResponse: null,
};
}
componentDidMount() {
apiHelper(URLredacted,JSONredacted)
.then(response => {
this.setState({
apiResponse: response
});
console.log("state set.",response)
});
}
render() {
const jsonResponse = JSON.stringify(this.props.apiResponse)
return (
<div>
<img className="logoheader" src = {logo}/>
<ColoredLine color="grey"/>
<p>{jsonResponse && ""}</p>
</div>
);
}
}
if these code dont work you will be need asyn function because you need to wait to fetch data.

Method returning undefined even though fetch succeeds?

I have two components, Client and App, and a fetch function. App is the child component of Client. I want to update Client's state using the return value from the method App calls. However, Client's state response is undefined after the fetch. I'm not sure why this code does not work.
import React, { Component } from 'react';
import './App.css';
function post(user, token, data){
console.log('fetching...')
fetch(`/project`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic '+ btoa(user+':'+token),
},
body: JSON.stringify(data)
}).then(r => {
if (!r.ok)
throw Error(r.status);
r.json().then(r => {return(r)});
}).catch(error => {throw Error(error)})
}
class Client extends Component {
constructor(props) {
super(props);
this.state = {
user: '',
token: '111',
project: {'project':'demo'},
response: {},
};
this.updateState = this.updateState.bind(this);
};
updateState(){
const { user, token, project } = this.state;
post(user, token, project).then(text => this.setState({ response: text
}));
}
render() {
return (
<App updateState={this.updateState}/>
)
}
}
class App extends Component {
render() {
return (
<div className="App">
<button onClick={ () => {
this.props.updateState()} }>Fetch Project</button>
</div>
);
}
}
EDIT: I changed my post() to this and it works :)
async function post(user, token, data){
console.log('fetching...')
const response = await fetch(`/project`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic '+ btoa(user+':'+token),
},
body: JSON.stringify(data)
}).catch(error => {throw Error(error)});
if(!response.ok)
throw Error(response.status);
const obj = await response.json();
return(obj);
}
If you are working with promises, you can do something like this.
import React, { Component } from "react";
async function post() {
// fetch //
return await fetch("https://hipsum.co/api/?type=hipster-centric");
}
class Client extends Component {
constructor(props) {
super(props);
this.state = {
response: "12"
};
this.updateState = this.updateState.bind(this);
}
async updateState(res) {
const text = await res().then(res => res.text());
this.setState({ response: text });
}
render() {
return (
<>
{this.state.response}
<App updateState={this.updateState} />
</>
);
}
}
class App extends Component {
render() {
return (
<div>
<button
onClick={() => {
this.props.updateState(post);
}}
>
Fetch
</button>
</div>
);
}
}
export default Client;
sandbox
It will be nice to know all the code for the fetch function but I think the problem is mostly here:
this.props.updateState(post())
That call is synchronous and the fetching process isn't. You need a better approach with await or promises or a callback.

React API returns empty

fairly new to react but I have the following API data I want to create as a list or whatever:
https://jsonblob.com/53c7f296-d79d-11e8-839a-a312b719c60a
My react component looks like this:
class Contacts extends Component {
constructor(props) {
super(props)
this.state = {
contacts:[]
}
}
componentDidMount() {
fetch('https://api.billysbilling.com/v2/contacts?organizationId=kZeGqbBRSXyeeDoWNkF3jQ',{
headers: {
'X-Access-Token': API_KEY,
'Content-Type': 'application/json'
},
})
.then(response => {
return response.json();
})
.then(response => console.log(response))
.then(d => {
this.setState({ contacts: d });
console.log("state", this.state.contacts)
})
}
render() {
return (
<div>
{
this.state.contacts.map(((contact, index) =>
<th key={`${contact.contact}${index}`}>
<div>
<div>
{contact.contact}
</div>
</div>
</th>
))
}
</div>
);
}
But however it seems to return nothing.
The console.log actually shows the data, so I am pretty stuck.
It would be awesome if some of you could help.
The state also just returns an empty array in the react tools in chrome.
When you write then(response => console.log(response)), you are not returning anything, so d will be undefined in the function given to the following then.
You could write it like this instead:
fetch('https://api.billysbilling.com/v2/contacts?organizationId=kZeGqbBRSXyeeDoWNkF3jQ',{
headers: {
'X-Access-Token': API_KEY,
'Content-Type': 'application/json'
},
})
.then(response => {
return response.json();
})
.then(d => {
console.log(d);
this.setState({ contacts: d.contacts });
});

ReactJS, multiple fetches and rendering the data

I'm pretty new to React and I've been struggling with fetching the data for quite a few days for my first React project.
I basically have a list of cards, split in two components: CardsList and Card. What I'm trying to do is to get the data for each card. My problem is, that I barely understood how fetching works for a single endpoint, and trying to fetch data from multiple endpoints at the same time seems to beat me.
I tried following an example from a blog explaining fetch, and came up with this:
export default class CardsList extends React.Component {
constructor(props) {
super(props);
this.state = {
details: [],
attachments: []
};
}
componentDidMount() {
//API and DEFAULT_QUERY have been set here, don't mind the ellipses
var API = '...';
var DEFAULT_QUERY = this.props.data;
var apiRequest1 = fetch(API + DEFAULT_QUERY, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
}).then(response => response.json());
var apiRequest2 = fetch(API + DEFAULT_QUERY + '_attachment', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
}).then(response => response.json());
var combinedData = {"apiRequest1":{},"apiRequest2":{}};
Promise.all([apiRequest1, apiRequest2]).then( values => {
combinedData["apiRequest1"] = values[0];
combinedData["apiRequest2"] = values[1];
return combinedData;
});
}
render() {
const { combinedData } = this.state;
let list = [];
for(var item of combinedData["apiRequest2"]) {
list.push(
<Card data={item} key={list.length}/>
);
}
return (
<div className="container">
<div className="row">
{list}
</div>
</div>
);
}}
As a first attempt I tried to feed the card component only the data from the second fetch. The console shows: "Uncaught TypeError: Cannot read property 'apiRequest2' of undefined".
I'm trying to learn a little bit from everywhere but I'm probably making things more confusing. What am I doing wrong and how should I go about this? Apologizes if I might seem confusing too.
EDIT: On the first fetch I'm trying to get the title, author and date of the card and on the second fetch I'm trying to get the preview image of the card.
The first fetch is something like this:
data:[{title: "test", body: "test", author: "1", id: "1",...},…
and the second fetch:
data:[{image_url: "abc.png", id: "1",...},...
The problem is in this line
const { combinedData } = this.state;
It equals to this
var combinedData = this.state.combinedData;
and I'm sure that this.state.combinedData is undefined; so this exception is thrown
Uncaught TypeError: Cannot read property 'apiRequest2' of undefined"
You'll need to add the default value for this.state.combinedData at the constructor so that the first render won't fail. After that you'll need to call
this.setState({
combinedData: ... // your data
})
at somepoint when your fetch request resolves.

How to make a rest post call from ReactJS code?

I am new to ReactJS and UI and I wanted to know how to make a simple REST based POST call from ReactJS code.
If there is any example present it would be really helpful.
Straight from the React Native docs:
fetch('https://mywebsite.example/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
(This is posting JSON, but you could also do, for example, multipart-form.)
Also see docs for ReactJS AJAX FAQs if not using React Native.
React doesn't really have an opinion about how you make REST calls. Basically you can choose whatever kind of AJAX library you like for this task.
The easiest way with plain old JavaScript is probably something like this:
var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.send(data);
In modern browsers you can also use fetch.
If you have more components that make REST calls it might make sense to put this kind of logic in a class that can be used across the components. E.g. RESTClient.post(…)
Another recently popular packages is : axios
Install : npm install axios --save
Simple Promise based requests
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
you can install superagent
npm install superagent --save
then for make post call to server
import request from "../../node_modules/superagent/superagent";
request
.post('http://localhost/userLogin')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ username: "username", password: "password" })
.end(function(err, res){
console.log(res.text);
});
As of 2018 and beyond, you have a more modern option which is to incorporate async/await in your ReactJS application. A promise-based HTTP client library such as axios can be used. The sample code is given below:
import axios from 'axios';
...
class Login extends Component {
constructor(props, context) {
super(props, context);
this.onLogin = this.onLogin.bind(this);
...
}
async onLogin() {
const { email, password } = this.state;
try {
const response = await axios.post('/login', { email, password });
console.log(response);
} catch (err) {
...
}
}
...
}
I think this way also a normal way. But sorry, I can't describe in English ((
submitHandler = e => {
e.preventDefault()
console.log(this.state)
fetch('http://localhost:5000/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
}
https://googlechrome.github.io/samples/fetch-api/fetch-post.html
fetch('url/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
Here is a the list of ajax libraries comparison based on the features and support.
I prefer to use fetch for only client side development or isomorphic-fetch for using in both client side and server side development.
For more information on isomorphic-fetch vs fetch
Here is a util function modified (another post on stack) for get and post both. Make Util.js file.
let cachedData = null;
let cachedPostData = null;
const postServiceData = (url, params) => {
console.log('cache status' + cachedPostData );
if (cachedPostData === null) {
console.log('post-data: requesting data');
return fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then(response => {
cachedPostData = response.json();
return cachedPostData;
});
} else {
console.log('post-data: returning cachedPostData data');
return Promise.resolve(cachedPostData);
}
}
const getServiceData = (url) => {
console.log('cache status' + cachedData );
if (cachedData === null) {
console.log('get-data: requesting data');
return fetch(url, {})
.then(response => {
cachedData = response.json();
return cachedData;
});
} else {
console.log('get-data: returning cached data');
return Promise.resolve(cachedData);
}
};
export { getServiceData, postServiceData };
Usage like below in another component
import { getServiceData, postServiceData } from './../Utils/Util';
constructor(props) {
super(props)
this.state = {
datastore : []
}
}
componentDidMount = () => {
let posturl = 'yoururl';
let getdataString = { name: "xys", date:"today"};
postServiceData(posturl, getdataString)
.then(items => {
this.setState({ datastore: items })
console.log(items);
});
}
Here is the simple method to define and call post APIs in reactjs. Install axios using command npm install axios and call post req method wherever you want, it will return array that contains 100 elements.
// Define post_req() Method in authAction.js
import axios from 'axios';
const post_req = (data) => {
return new Promise((resolve, reject) => {
const url = 'https://jsonplaceholder.typicode.com/posts'
const header = {
"Access-Control-Allow-Origin": "*",
"Content-Type: application/json"
}
axios({
method: 'post',
url: url,
data: data,
headers: header
});
.then((res)=>{resolve(res);})
.catch((err)=>{reject(err);})
})
}
// Calling post_req() Method in react component
import React, { Component } from 'react';
import { post_req } from 'path of file authAction.js'
class MyReactComponent extends Component {
constructor(props) {
super(props);
this.state = {
myList:[]
};
}
componentDidMount() {
let data = {
.......
}
this.props.post_req(data)
.then((resp)=>{this.setState({myList:resp.data})})
.catch((err)=>{console.log('here is my err',err)})
}
render() {
return (
<div>
....
</div)
}
}
export default MyReactComponent;
import React ,{useState}from 'react';
import Axios from 'axios';
export default function Formlp()
{
const url ="";
const [state, setstate] = useState({
name:"",
iduser:""
})
function handel(e){
const newdata={...state}
newdata[e.target.id]=e.target.value
setstate(newdata);
}
function submit(e)
{
e.preventDefault();
// Axios.post(url,{name:state.name,iduser:state.iduser}).then( res=>{console.log(res)});
console.log(state)
}
return (
<div onSubmit={ (e)=> submit(e)}>
<input onChange={ (e)=>handel(e) } id="name" value={state.name} placeholder="name" type="text" >
<input onChange={ (e)=>handel(e) } id="iduser" value={state.iduser} placeholder="iduser" type="text" >
<button>submit</button>
</form>
</div>
);
}
Here is a quick example for v18+ while handling form data and creating a POST request with the data.
async function handleOrderSubmit(event){
event.preventDefault()
try{
const formData= {name: event.target.name.value, email: event.target.email.value, message: event.target.name.message}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
};
const response = await fetch('https://www.example.com/form', requestOptions);
const data = await response.json();
navigate("/form-response", { state: {data: data, status: true} })
}
catch(error){
navigate("/form-response", { state: {status: false} })
}
}
Note 1: Using status on '/form-response' page, you can customise what to show user. For true, you can show a different section and for false a different one.
Note 2: If the status is successful, you can access data on the next page also and customise it according to user information.
Note 3: event.preventDefault() is important to avoid page reloading.
Here is an example: https://jsfiddle.net/69z2wepo/9888/
$.ajax({
type: 'POST',
url: '/some/url',
data: data
})
.done(function(result) {
this.clearForm();
this.setState({result:result});
}.bind(this)
.fail(function(jqXhr) {
console.log('failed to register');
});
It used jquery.ajax method but you can easily replace it with AJAX based libs like axios, superagent or fetch.

Resources