Need help mapping in json fetch - reactjs

Can anyone see where I mess up this fetch?
Error message; TypeError: Cannot read properties of undefined (reading 'map')
This is how the data looks like
Happy for any help!
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
export const PressReleaseList = () => {
const [pressReleases, setPressReleases] = useState([null]);
useEffect(() => {
(async function () {
try {
const res = await fetch(
'https://feed.mfn.se/v1/feed/3XXXXX.json'
);
const json = await res.json();
setPressReleases(json.items);
} catch (e) {
console.error(e);
}
})();
}, []);
return (
<Main>
{pressReleases.items.map((item) => (
<TextCell key={item.news_id}>
<CategoryText>{item.title}</CategoryText>
</TextCell>
))}
;
</Main>
);

You are trying to access twice to items. Try setting setPressReleases only with the json variable or apply the map function to pressReleases directly.
And given the error code in your comment, we can see that you are trying to render a list (item.subjects) in a JSX Element instead of primitives.

Double check your key={item.news_id}. Looks like item is missing an 's,' should be key={items.news_id} based off your screenshot.

Initially when your loop runs (before the Ajax call completes), it's running the .map on an array whose only child is a null (derived from const [pressReleases, setPressReleases] = useState([null]);).
Within your loop, when you're calling item.news_id you're essentially doing null.news_id thus your app crashes.
Change your useState to the following:
const [pressReleases, setPressReleases] = useState([]);
This will ensure you have an empty array, thus you don't ever loop until you have data.

Related

Difficulties with useEffect and asyncawait

I've read several questions here regarding my current difficulty; they also told me the way I was coding it was wrong, and I changed it. However, even after changing I still can't seem to get the proper result.
I'm trying to make a small React HTTP Request app for learning purposes. According to the classes I've been following, I managed to create the json server, setup to watch for the DB.json properly, etc. Now, inside the App.js I'm trying to make the async\await call for listing the products in the console.
First, I had the following error:
"Effect callbacks are synchronous to prevent race conditions. Put the async function inside:"
I fixed it by changing my code. It was triggering a warning and I found out the classes I've been following are a bit outdate. No problem. However, even after changing it I can't view the products I create on db.json. If I go to localhost:3000/products it shows up there (which means things are working).
I believe I'm doing it the right way now, but I still can't seem to figure out why I can't view the data.
Any input is appreciated. Thanks!
ps: I'm just starting with react.
App.Js
import './App.css';
import { useState, useEffect } from "react";
const url="http:/localhost:3000/products";
function App() {
const [products, setProducts] = useState ([]);
useEffect(() => {
const fetchData = async () => {
const data = await fetch(url);
console.log("Data:" + data)
const res = await data.json();
console.log("Res:" + res)
setProducts(res);
}
fetchData();
}, []);
console.log(products);
return (
<div className="App">
<h1>LIsta de produtos</h1>
</div>
);
}
export default App;
The URL you put is missing a "/", Check if the URL is right, rest else seems to be correct, the code below should work.
import "./App.css";
import { useState, useEffect } from "react";
// URL is probably wrong, this is fixed URL
const url = "http://localhost:3000/products";
function App() {
const [products, setProducts] = useState([]);
useEffect(() => {
const fetchData = async () => {
const data = await fetch(url);
console.log("Data:" + data);
const res = await data.json();
console.log("Res:" + res);
setProducts(res);
};
fetchData();
}, []);
console.log(products);
return (
<div className="App">
<h1>LIsta de produtos</h1>
</div>
);
}
export default App;

Pull data from firestore using useEffect works on re-render only

Here is my code:
import React, { useEffect, useState } from 'react';
import { getDocs, collection } from 'firebase/firestore';
import { db } from '../firebase-config';
const Home = () => {
const [postList, setPostList] = useState([]);
const postsCollectionRef = collection(db, "data");
useEffect(() => {
const getPosts = async () => {
const data = await getDocs(postsCollectionRef);
let postListArray = []
data.forEach((doc) => {
const post = { ...doc.data() }
postListArray.push(post)
});
setPostList(postListArray)
};
getPosts();
console.log(postList);
}, []);
return (
<div>test</div>
);
};
export default Home;
On loading, the console.log returned an empty array. The spooky thing is when i changed anything , for example
return (
<div>test_epic</div>
);
The console.log shows that it is an array. Anyone has any idea as to why? Please refer to the screepcap as attached.
the first render on loading
I changed anything and components rerendered
Setting state in react is asynchronous, so the data is loaded and the state is set but the console.log statement is executed before the setting state async operation is complete
To make it a bit more clear this is how it works step by step
Component is rendered and postList is initialized with a value of []
useEffect is triggered
Data is fetched
A call to set a new value of postList is placed using setPostList (key here is a call is placed not that the data is actually updated)
You print console.log with a value from Step 1
The call from Step 4 is complete and now the data is actually updated
Here is an article that explains it with examples
And here is another answer that explains this deeply

useEffect not being executed in React

This seems to be a common problem but somehow I simply cannot get it to work : I am trying to read some data from a mongoDB database. If I call the NodeJS server directly in a browser, as in
http://localhost:5000/record/nilan
I get the data as a JSON string:
{
"pid":{
"ck":"F19909120:525.522.8788.37",
"name":"nilan",
"cID":"0SL8CT4NP9VO"
}
}
But when I am calling this from a React function RecordDetails(), I get nothing. Please see the code below :
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { useParams, useNavigate } from "react-router";
export default function RecordDetails() {
const params = useParams();
const [record1, setRecords] = useState([]);
window.alert('here1');
// This method fetches the records from the database.
useEffect(() => {
async function get1Record() {
//const id = params.id.toString();
const response = await fetch(`http://localhost:5000/record/${params.id.toString()}`);
if (!response.ok) {
const message = `An error occurred: ${response.statusText}`;
window.alert(message);
return;
}
const record1 = await response.json();
const message2 = 'here'
window.alert(message2);
window.alert(record1.pid.name);
window.alert(record1.pid.ck);
setRecords(record1);
}
get1Record();
return;
} , [record1.length]);
window.alert('here2');
// This following section will display the table with the records of individuals.
return (
<div>
<h3>Record Details</h3>
{record1.pid.name}
{record1.pid.ck}
{record1.pid.cID}
</div>
);
}
The process does not seem to be entering the useEffect() part of the code .
When this function RecordDetails() is called, we get the alerts in this sequence. "here1", "here2", "here1", "here2"; then the functions terminates with a blank screen.
I do not get any of the alerts from inside the useEffect, not even the error message alert. What am I doing wrong?
The useEffect hook only runs after the DOM has rendered and when the values inside the dependency array have changed; since you don't change the values inside the dependency array anywhere except within the useEffect hook, it never runs because record1.length will never change -- the code is never reached. You may want to use the useMemo hook instead, which runs once and then will only change when its dependency changes. Also, in order to get it to update, you need to trigger the change from outside the hook, not within, otherwise it will not run. Thus, may I suggest something along the following:
const userInfo = useMemo(() => {
const response = //make server call
return response
}, [dependentValues]);
setRecords({record1: userInfo});
return (
<div onChange={() => {changeDependentValues()}} />
)

react doesn't render latest value

For the initial render, I have object date, which is an empty array. I then try to get data from an influxDB, but the get result isn't reflected by React with a re-render. The get function is calling in useEffect (you can see this in screenshots). I use typescript, and to avoid getting an error on the initial load (that data is an empty array of objects and it doesn't have a value property) I use the typescript syntax, but it still doesn't display the correct value. It doesn't display anything at all.
What could be the problem? In the last photo, we can see another way to display data without a question mark from typescript, but it doesn't work correctly either, even if the length of the array is greater than 0, it still doesn't display data[0].value.
Initial data:
Data after DB get:
Get the first element in array:
Browser result (before ':' we should see data[0].value):
Alternate way (when data isn't empty we should see the value of the first object in array):
I also show we code
import React from 'react';
import './App.css';
import { FluxTableMetaData } from '#influxdata/influxdb-client';
const { InfluxDB } = require('#influxdata/influxdb-client');
export const App = () => {
debugger
const authData = {
token: 'Emyw1rqUDthYRLpmmBc6O1_yt9rGTT57O50zoKiXUoScAjL6G-MgUN6G_U9THilr86BfIPHMYt6_KSDNHhc9Jg==',
org: 'testOrg',
bucket: 'test-bucket',
};
const client = new InfluxDB({
url: 'http://localhost:8086',
token: authData.token,
});
const queryApi = client.getQueryApi(authData.org);
const query = `from(bucket: "${authData.bucket}") |> range(start: -1d)`;
const data: any[] = [];
React.useEffect(() => {
queryApi.queryRows(query, {
next(row: string[], tableMeta: FluxTableMetaData) {
debugger;
const o = tableMeta.toObject(row);
const item = {
time: o._time,
measurement: o._measurement,
field: o._field,
value: o._value,
};
return data.push(item);
},
error(error: Error) {
return error;
},
complete() {
console.log(data)
return data;
},
})
},[]);
debugger;
return (
<div>
<div>{data.length !== data[0].value}:</div>
<div>hello</div>
</div>
);
};
another way:
<div>
<div>{data[0]?.value}:</div>
<div>hello</div>
</div>
The main issue in your code is, You have defined data as a const variable, and not as a state. Thus, in useEffect, even if your data gets changed, it will not reflect on data[0].value as it is a const variable and react doesn't render updated values of variables. It updates/renders only if it's a state.
In short, Convert your const data to be a stateand use setState like below for your code to work!
const [data, setData] = React.useState([]);
...
setData([...data , item]);
I suggest you use the React States for that in the following way
var [nameOfVariableWhichWillChange, changeFunction] = React.useState("");
now whenever whichever function wants to change the value of that function just use changeFunction(newValueOfVariable)
the plus point of using React state is wherever you might have used that variable on change of That variable each instance will change on its own...
Do let me know does that solve your problem, or you need something else
React doesn't re-render the webpage even if the data has changed. You need to store your data inside a React.useState and call setState to trigger a re-render.
const [data, setData] = useState([])
React.useEffect(() => {
...
next(row: string[], tableMeta: FluxTableMetaData) {
...
setData([...data, item])
},
...
Read about useState here for more information: https://reactjs.org/docs/hooks-state.html

how to make an object with multiple object an array in state?

This is my code,
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./App.css";
function App() {
let [albums, setAlbums] = useState([]);
useEffect(() => {
const key = "blablabla to keep secret";
const fetchData = async () => {
const result = await axios(
`http://ws.audioscrobbler.com/2.0/?method=artist.gettopalbums&artist=cher&api_key=${key}&limit=10&format=json`
);
setAlbums(result.data.topalbums);
console.log(albums, "data?");
// const { data } = props.location.state;
};
fetchData();
}, []);
return <div className="App"></div>;
}
export default App;
the data I am fetching is in an object with objects inside, in-state I initialized with an empty array, and then after I fetched the data I use setAlbums. I have two problems, the console.log after I fetch just shows me an empty array, but when I console log in render I do get the data but it is an object and not an array of objects, so I can't even map over it, how do I fix this?
Try to do something like this:
setAlbums(album => [...album, results.data.topalbums])
that way you can push results to your array instead of transforming it into object
also if you wish to see updated album then create something like:
useEffect(() => {
console.log(albums)
},[albums])
as setting state is asynchronous therefore it doesn't happen immediately as Brian mentioned, so this code will launch if albums state changes its value

Resources