fetching data with react hook returns undefined on nested obj properties - json

Im trying to display data that has been fetched. but i cannot seem to display nested objects properties in react. Any ideas? if i log the data i first get a undefined, then the correct data.
my guess is that i need to wait for the data to be loaded then display it. but it does work for the title that is not in a nested obj.
function SingleBeneficiary({ match }) {
const [data, setData] = useState({ data: []});
const id = match.params.id
useEffect(() => {
async function fetchData() {
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
setData(jsonData)
}
fetchData();
}, [])
return (
{data.title} // works
{data.address.careOf} // dont work
The data
{
"title":"myTitle",
"address":{
"careOf": "my adress"
}
}

Can you try like this?
I set initial data to null, and in return I check if it is not null.
If address can be null, additional null check is required.
function SingleBeneficiary({ match }) {
const [data, setData] = useState(null);
const id = match.params.id
useEffect(() => {
async function fetchData() {
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
setData(jsonData)
}
fetchData();
}, [])
return (
<div>
{data && (
<div>
<p>data.title</p>
<p>data.address.careOf</p>
</div>
)}
</div>
);
}

You should check if address has careOf property before using it because first time data will be undefined and in second render it will have the data after the api call.
{data.address && data.address.careOf}

For anyone who is having a similar issue(i.e. fetching data via api and only the first time it runs, it will show the data as undefined but after manual refreshing, it works fine), here is a quick and sketchy addition you might consider alongside with 1. "Inline If with Logical && Operator" method and 2. using useState for checking if the api loading is over. With those three, mine worked.
Try fetching the desired data in the previous page of your app; in this case, add the following lines in any page you'll see before "SingleBeneficiary".
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
Maybe it has to do with npm cache, but not really sure what's going on.

replace
return (
{data.title}
{data.address.careOf}
)
with
return (
{data?.title}
{data?.address?.careOf}
)

Related

Why am I unable map JSON object data in Next.js?

I am trying to display some JSON data that I receive from my backend. I first have a useEffect which retrieves the JSON data:
const [backendData, setBackendData] = useState(null)
useEffect(() => {
const fetchUserData = async () => {
const response = await fetch('http://localhost:5000/api/userData/')
const json = await response.json()
// check if response is ok
if (response.ok) (
setBackendData(json)
)
}
fetchUserData()
console.log(backendData, 'hi')
}, [])
And then in my JSX code I want to display the _id of the object which has a structure that looks like this:
by using this line of code:
{backendData && backendData.map((userData) => {
<p key={userData._id}>{userData._id}</p>
})}
I am unsure as to why this line of code doesn't work though because I don't see any output on the next.js page. I am able to receive the backend data as I see the object in my console when I log it but when I try mapping it, it doesn't work. Does anyone know why?
I figured out why, you have to return a value when you map in next.js so the solution would be:
{backendData && backendData.map((userData) => {
return (
<p key={userData._id}>{userData._id}</p>
)
})}

Loop through json object and display the data with React?

The api response i get back has 10 objects of people inside it and i would like react to display the Persons name and gender. I'm not sure how to accomplish this. Is states even the right way to go about this or should i try to save my response inside of an array only?
Any help is appreciated.
state = {
Person: null,
Gender: null
}
async componentDidMount() {
const url = "**********************************************";
const response = await fetch(url);
const data = await response.json();
this.setState({Person: data[0].Name})
this.setState({Gender: data[0].Gender})
}
render() {
return <div>
<p>
{this.state.Person}
</p>
<p>
{this.state.Gender}
</p>
}
}
Yes, you should store your data in state and map it to display the name and gender of each person.
async componentDidMount() {
const url = "**********************************************";
const response = await fetch(url);
const data = await response.json();
this.setState({ data })
}
render() {
return(
{this.state.data.map((el, id)=>
<div>
<p>Name:{el.Name}</p>
<p>Gender:{el.Gender}</p>
</div>
)}
)}
Should definitely use an array of "Persons", also try using hooks :)

Batching with useQuery react hooks getting back undefined

I am currently working on a project which requires me to make multiple queries/mutations. I tried setting up my apollo client with BatchHttpLink and I can see the data I am requesting in the network tab in the browser. It is coming back at an array of objects instead of JSON.
But the issue is when I try to grab the data in my component data is undefined. I tried using HttpLink instead of BatchHttpLink and I can get the data back from the hook.
My suspicion is the shape of the object that comes back from the response is different, I tried looking into documentation but I can't find much about batching.
Currently using "#apollo/client#^3.0.2"
Here's my client set up.
import { ApolloClient, InMemoryCache, ApolloLink, from } from '#apollo/client'
import { BatchHttpLink } from '#apollo/client/link/batch-http'
import { onError } from '#apollo/client/link/error'
const BASE_URL = 'http://localhost:4000'
const httpLink = new BatchHttpLink({
uri: BASE_URL,
credentials: 'include',
})
const csrfMiddleware = new ApolloLink((operation, forward) => {
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
'X-CSRF-Token': getCSRFToken(),
},
}))
return forward(operation)
})
const errorMiddleware = onError(({ networkError }) => {
if (networkError && 'statusCode' in networkError && networkError.statusCode === 401) {
window.location.assign('/accounts/login')
}
})
const client = new ApolloClient({
link: from([errorMiddleware, csrfMiddleware, httpLink]),
cache: new InMemoryCache(),
})
This is the react hook I'm trying to console log.
const {data} = useQuery(GET_USER_PERMISSIONS_AND_PREFERENCES)
Figured it out. You need to add another middleware to return the data that the useQuery hook can recognize. The data that comes back in the batch call is an array of objects shaped
{
payload: {
data: { ... }
}
}
So something like this did the trick for me
const batchParseMiddleware = new ApolloLink((operation, forward) => {
return forward(operation).map((data: any) => data.payload)
})
I have been having a similar issue, and have so far only been able to solve it by breaking batching and converting to a normal HttpLink

I'm getting a 404 error when trying to render my results for my API Hack assignment

I'm working on an API Hack assignment for my class with Thinkful and my issue has been that I've been trying to make a call to spoonacular's food api and render the results onto the DOM. However, when I try to do that, All I get in return is a 404 error. I'm wondering if i did something wrong or is some unforeseen problem that is beyond my control?
I've already look at manually typing the composed URL and postman as well.
function queryParams(params) {
const queryItems = Object.keys(params).map(key => `${encodeURIComponent(key)}= ${encodeURIComponent(params[key])}`)
return queryItems.join('&');
}
function displayResults(responseJson){
console.log(responseJson);
$('#results-list').empty();
for(let i = 0; i < responseJson.results.length; i++){
$('#results-list').append(
`<li><h3>${responseJson.results[i].id},${responseJson.results[i].protein}</h3>
<p>By ${responseJson.results[i].calories}</p>
<img src='${responseJson.results[i].image}'>
</li>`
)};
$('#results').removeClass('hidden');
};
function getRecipe(query,maxResults,){
const params ={
q:query,
number: maxResults,
};
const queryString = queryParams(params)
const url = searchUrl+'?'+ queryString +'?apiKey='+ apikey;
console.log(url);
fetch(url,option)
.then(response =>{
if(response.ok){
return response.json();
}
throw new Error(response.statusText);
})
.then(response => console.log(responseJson))
.catch(err =>{
$('#js-error-message').text(`Something went wrong: ${err.message}`);
});
}
function watchForm() {
$('form').submit(event => {
event.preventDefault();
const searchRecipe = $('.js-search-recipe').val();
const maxResults = $('.js-max-results').val();
getRecipe(searchRecipe, maxResults);
});
}
$(watchForm);
It looks like you have a couple issues:
First, you're constructing an invalid url:
const url = searchUrl+'?'+ queryString +'?apiKey='+ apikey;
notice the 2 ?s
Also, when you're constructing the query params, you're adding a space between the = and the value of your param
${encodeURIComponent(key)}= ${encodeURIComponent(params[key])}
If you're using the correct path and a valid API key, fixing those things may be enough to make it work.

Empty GET response on requesting JSON file's content | koa2

I am a new to koa2, and I trying to GET the contents of a JSON file with koa2
app.use( async ( ctx ) => {
let url = ctx.request.url;
if (url == "list") {
let res = ctx.request.get('http://domain/hello.json');
ctx.body = res.body;
}
})
The JSON file hello.json looks like the following:
{"da": "1212", "dad": "12addsf12"}
I want the route /list to return the contents of hello.json, however, the response is empty. What do I do?
Update:
Change the following lines of code:
let res = ctx.request.get('http://domain/hello.json');
ctx.body = res.body;
to:
let res = ctx.get('http://domain/hello.json');
ctx.body = res;
You should get the content now.
Koa by itself does not support routing, only middleware, you need to have a router middleware for that, try koa-router.
Your app would look something like
const route = require('koa-route')
app.use(route.get('/list', ctx => {
// Route handling logic
});
Also note that ctx.get is an alias for ctx.request.get which returns header information.
This may not be Koa's way of doing things, but this is what I tried and worked for me (complete code for noobs like me):
// jshint ignore: start
const koa2 = require("koa2");
const router = require('koa-simple-router');
const app = new koa2();
const request = require('request-promise-native');
// response
app.use(router(_ => {
_.get('/list', async (ctx) => {
const options = {
method: 'GET',
uri: 'http://www.mocky.io/v2/5af077a1310000540096c672'
}
await request(options, function (error, response, body) {
// I am leaving out error handling on purpose,
// for brevity's sake. You must in your code.
ctx.body = body;
})
});
}));
app.listen(3000);
And, like what J Pichardo's answer points out, Koa by itself does not support routing. You need to use some routing middleware.