useEffect not being executed in React - reactjs

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()}} />
)

Related

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

Need help mapping in json fetch

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.

React useState hook not updating with axios call

I am aware this is a common question as I have spent the last two hours going through every answer and trying to get my state to update but nothing is working.
I am fetching text from a cms however on first load the state is undefined and my app crashes. However if I comment the line out, load the page and uncomment the line the correct values are displayed.
Here is some of the code I have tried.
The data i am hoping to get
[
{id:1},
{id:2},
{id:3},
{id:4},
]
import react, {useEffect, useState} from 'react'
import axios from 'axios'
const [carouselTitle, setCarouselTitle] = useState([])
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
await axios('api').then(
response => {
console.log(response.data)
setCarouselTitle(response.data)
console.log(carouselTitle)
})
};
return(
<h1>{carouselTitle[1].id}</h1>
)
console logging the data works fine but when i console log the state it does not work.
2ND METHOD I TRIED
useEffect(() => {
const fetchData = async () => {
const res = await axios('api');
const carouselTitleAlt = await res.data;
setCarouselTitle({ carouselTitleAlt });
console.log(carouselTitleAlt);
console.log(carouselTitle);
};
fetchData();
}, []);
Again console logging the const inside the useEffect displays the correct information but logging the state does not work.
Appreciate your responses or better ways of displaying the data.
setState is asynchronous : https://reactjs.org/docs/faq-state.html#why-doesnt-react-update-thisstate-synchronously
It means that you cannot expect to console.log the new state value the line after you called setCarouselTitle.
To log the new value, you could use another useEffect, with carouselTitle in the dependencies array, where you console.log(carouselTitle) :
useEffect(() => {
console.log(carouselTitle);
}, [carouselTitle]);
That said, your component should behave correctly, it will be refreshed when the state is updated.
In the JSX you should check that carouselTitle is not undefined (meaning that the request failed or is still pending) :
{carouselTitle && <H1>{carouselTitle[0].id}}
https://reactjs.org/docs/conditional-rendering.html#gatsby-focus-wrapper
First of all, if you pass an empty array for initial data to useState, you can't get any item in that array in here:
return(
<h1>{carouselTitle[1].id}</h1>
)
Because component returns first item of an array that has nothing. I prefer to you do it like this:
return(
<h1>{carouselTitle.length > 0 && carouselTitle[0].id}</h1>
)
And also based on this and official documentation, setState (and also setSomthing() using useState()) is asynchronous.
So state data doesn't show immediately after setting that.
You should trigger useEffect for run fetch function
useEffect(()=>{fetchData();},[carouselTitle])

React useEffect memory leak, second argument

I am fetching data inside of useEffect, with intention to update useState with data obtained. I kept getting null inside of oneCrypto state value even though console log showed that data was received. Realized it has to do with second argument missing in useState. When add [] empty array, my oneCrypto shows null. When I set [oneCrypto] inside the array, as a dependency, my app crashes - too many requests, console log prints data received over and over and I don't understand why... help please.
import React, { useState, useEffect } from "react"
import { useParams } from "react-router-dom"
export default function SingleCrypto() {
const [loading, setLoading] = useState(false)
const [oneCrypto, setOneCrypto] = useState(null)
const { id } = useParams()
useEffect(() => {
async function getOneCrypto() {
try {
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const response = await fetch(proxyurl +
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/info?id=" +
id,
{
headers: {
}
}
)
const data = await response.json()
const mydata = data.data;
setOneCrypto(mydata)
console.log(oneCrypto)
} catch (error) {
console.log(error)
}
}
getOneCrypto()
}, [oneCrypto])
return <>
<h1>I am Single Crypto page</h1>
</>
}
Calling setOneCrypto causes a rerender and since oneCrypto has changed since the previous render useEffect is called again and the process restarts. Inside the useEffect where you call console.log(oneCrypto) is happening before the value has been updated because the update happens between renders.
Try removing oneCrypto from the array passed in the second argument and call console.log outside your useEffect.
Your loop is:
1) |--> your async function call setOneCrypto ---|
2) |-- new value of oneCrypto call useEffect <--|
Might be you want one request if oneCrypto is null:
!oneCrypto && getOneCrypto();

How do I correctly implement setState() within useEffect()?

If this useEffect() runs once (using [] as the second parameter), setTicket(response.data) does not update the value of ticket with data. If I run useEffect() with [ticket] as the parameter, it updates the value of ticket with data, but useEffect becomes an infinite loop.
I need it to run once and update the ticket data. I don't think I understand useEffect() and its second parameter.
What do I do to get the expected result?
import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";
const EditTicket = (props) => {
const [ticket, setTicket] = useState("");
useEffect(() => {
axios
.get("http://localhost:4000/tickets/" + props.match.params.id)
.then((response) => {
setTicket(response.data);
console.log({ ticket });
})
.catch(function (error) {
console.log(error);
});
}, []);
return <div>edit</div>;
};
export default EditTicket;
ticket is a local const. It will never change, and that's not what setTicket is trying to do. The purpose of setTicket is to tell the component to rerender. On that next render, a new local variable will be created, with the new value.
Your code is already written the way it should be written, except that your log statement is not providing you with any useful information. If you want to see that it rerenders with the new value you could move the log statement to the body of the component.
const EditTicket = (props) => {
const [ticket, setTicket] = useState("");
console.log('rendering', ticket);
useEffect(() => {
// same as before

Resources