React cannot setState in useEffect - reactjs

const [soilInfo, setSoilInfo] = useState([]);
const [ambient, setAmbient] = useState([])
useEffect(() => {
const getSoil = () => {
axios.get("http://localhost:8081/soil_info").then((response) => {
setSoilInfo(response.data);
console.log(response.data);
})
}
getSoil();
console.log(soilInfo);
},[])
useEffect(() => {
const getAmbient = () => {
axios.get("http://localhost:8081/ambient").then((response) => {
setAmbient(response.data);
console.log(response.data);
})
}
getAmbient();
console.log(ambient);
}, [])
I tried debugging by printing in get function and after get function. It turns out that soilInfo and ambient are null sets. The response was fine. This is the results

I have a couple of ideas here:
Your axios get call could be failing. This would result in your then clause not being called. I would try logging out the response or adding a catch clause to verify the request is working.
Both setSoilInfo and setAmbient are expecting a list at the moment (if you are using Typescript at least). What data type is response.data? If you know, I'd recommend typing your useState like so: useState<TYPE[]>. Then you can get some type help.
Let me know if you have questions about either of the above.

Related

Using a POST request's response values in React Native

everyone. I'm a new developer and this is my first post here, so please bear with me.
What I'm trying to do is access the values that I received from a POST request that I made.
Below you can see what I'm trying to do. I set up a state where I'll store my data and then there's a function called fetchData that does a POST request and receives an object with the values, right?
Now I that I've received my object, I want to store its values in some of my variables.
Since the values have been stored in the 'data' state, I thought I would access its values by doing something like 'userName = data.userName', or something like 'age = data.userAge'. Obviously that didn't work out because my IDE does not know those values yet lol. So how do you think I should access them?
const [data, setData] = useState([{}]);
useEffect(() => {
fetchData({
ids: [0],
})
.then((response: any) => {
setData(response);
})
.catch((error: any) => {
console.log('error', error);
});
}, []);
dont place the function directly in useEffect, do something like this instead
const [data, setData] = useState([])
const getData = async() => {
try{
const response = await fetchData({ids: [0]});
setData(response);
}catch(error){
console.log(error);
}
}
useEffect(() => {
getData();
},[])

react-dom.development.js:86 Warning: useEffect must not return anything besides a function, which is used for clean-up

I can't find my error... Can anyone help me please?
const [testArtData, setTestArtData] = useState([]);
useEffect(() => {
const getMyNfts = async () => {
const openseaData = await axios.get(`https://testnets-api.opensea.io/assets?asset_contract_address=0x4Bef569089846759595C1ed598a3bD6D249FD7c4&order_direction=asc`);
console.log(openseaData.data.assets);
setTestArtData(openseaData.data.assets);
}
return getMyNfts()
}, [])
Everytime I get this error:
Error
You would help me so much! Thanks
The solution for this is to make a async function inside the useEffect itself and then call it underneath it:
useEffect(() => {
// wrap your async call here
const loadData = async () => {
setUsersLoading(true);
const result = await getUsers();
setUsers(result);
setUsersLoading(false);
};
// then call it here
loadData();
}, []);
However, React does not recommend it because everything in useEffect is to be executed in a seprate thread and thus returned value may be needed by some other part of code and there is a chance of un-predictable behavior.

Why my useEffect that tries to get blockchain data is looping infinitely and my async func still returns Promise pending

I am trying to use async await inside a useEffect hook getting some data from a testnet blockchain but I am getting 2 problems:
The async function returns a Promise, why is that? Shouldn't async await automatically resolve the promise and give me the data? I tried to solve it with Promise.resolve but not working, it still tells me campaigns is a Promise in pending state.
It enters in an infinite loop and I still do not get why.
Here is the code:
useEffect(() => {
const getCampaigns = async() => {
const campaigns = await factory.methods.getDeployedCampaigns().call()
return campaigns
}
const campaigns = getCampaigns();
setCampaigns(Promise.resolve(campaigns));
console.log('campaigns: ', campaigns);
})
You have no dependencies array.
useEffect(() => {
const getCampaigns = async() => {
const campaigns = await factory.methods.getDeployedCampaigns().call()
return campaigns
}
const campaigns = getCampaigns();
setCampaigns(Promise.resolve(campaigns));
console.log('campaigns: ', campaigns);
}, [])
Try this
useEffect(() => {
const getCampaigns = async() => {
const campaigns = await factory.methods.getDeployedCampaigns().call()
setCampaigns(campaigns);
}
getCampaigns();
}, []);
The empty array in useEffect call makes it behave like component did mount and only executes once (assuming factory methods are initialized on mount) and since the getDeployedCompanigns Promise is already resolved I'm simply setting the state in the getCampaigns function.
Read this article for details: https://devtrium.com/posts/async-functions-useeffect

useEffect not triggering but the template is being rendered somehow

I am getting too many re-renders while using react-hooks.
I am trying to fetch data from api by using a parameter in URL.
Here's the code:
export default function Details() {
const { title } = useParams();
const [loading, setLoading] = useState(true);
const [details, setDetails] = useState([]);
const [error, setError] = useState("");
function getDetails(keyword) {
if (keyword) {
setLoading(true);
fetch(
`API`
)
.then((res) => {
let result = res.data.results;
result = result.filter(function (result) {
return (result.title = keyword);
});
setDetails(result[0]);
setLoading(false);
console.log(details);
})
.catch((err) => {
setError(["Unable to fetch data"]);
setLoading(false);
});
}
}
getDetails(title)
return(
// template
)
now I think this is happening at the line where I call getDetails.
then I tried using useEffect to load the data only once after it is mounted,
useEffect(() => {
getDetails(title);
}, []);
It still is unable to fetch the data, as the getDetails function is never called.
How can I resolve this?
Edit:
Fixed one silly error.
Here's the codesandbox link:
Codesandbox
There are multiple issues with this, first you need to specify what you want to be notified about when the useEffect gets called again. You could do this by adding the variables you want within the array
useEffect(() => {
getDetails(title);
}, [
// Add what you want here
]);
The second issue you have is that you declared the detalis variable twice. Once using the set state here: const [details, setDetails] = useState([]);
The second time here:
const details = getDetails(title)
the code here has two obvious error beside the functionality problems you mentioned:
1 - you cannot declare two variables with same name using let or const; it will throw a SyntaxError
const [details, setDetails] = useState([]);
...
const details = getDetails(title)
2- getDetails function is written with a asynchronous mindset, and it will return nothing,
so details in const details = getDetails(title) will be set to undefined
Looks like your getDetails function has title param so I would add title and getDetails both in the dependency list of useEffects
Or place getDetails inside the useEffect
Here is your working code. You had multiple problems where res.data was undefined so you need to get res.results directly based on your response object
useEffect(() => {
function getDetails(keyword) {
if (keyword) {
setLoading(true);
fetch(
`https://api.jikan.moe/v3/search/anime?q=${keyword}&page=1&genre_exclude=0`
)
.then((res) => res.json())
.then((res) => {
console.log(res.results);
let result = res.results;
console.log(result);
result = result.filter(function (result) {
return (result.title = keyword);
});
setDetails(result[0]);
setLoading(false);
console.log(3);
})
.catch((err) => {
console.log(err);
setError(["Unable to fetch data"]);
setLoading(false);
});
}
}
console.log('calling getDetails')
getDetails(title);
}, [title]);
Note: tested in the code sandbox link provided in the question. Its working code.

setState never gets set in useEffect after API call responds with data

I'm trying to update state immediately after data comes in from the API. The data is coming in, I can see it using the console.log right below my API request. All of the data is right but for some reason, setState never sets in my hook. It just returns and empty array even after the console displays data.
const [experienceData, setExperienceData] = useState([]);
const { match = {} } = props;
useEffect(() => {
async function fetchData() {
if (Object.keys(match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData(response)
}
}
fetchData();
}, []);
I must be doing something wrong but I can't figure out what that is. Hoping someone on here has run into the same issue.
UPDATE: I just changed everything over the a class and duplicated the exact code on another file and ran into the exact same issue. The console updates with the data, but the setState on the line immediately after the data does not setState.
async componentDidMount() {
if (Object.keys(this.props.match.params).length > 0) {
const response = await ApiService.getExperiences(this.props.match.params.experieneId);
console.log(response[0])
this.setState({ experienceData: response[0], occurrenceData: response[0].occurrences });
}
}
You have to useSetState in a proper way, the issue is in the setExperienceData
const [experienceData, setExperienceData] = useState({response:""});
const { match = {} } = props;
useEffect(() => {
async function fetchData() {
if (Object.keys(props.match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData(experienceData => ({ ...experienceData, response: response }));
}
}
fetchData();
}, []);
return(<div>check {experienceData.response}</div>)
I see you left the dependency array empty. This tells React to run this effect only once: when the component first renders. If you want your useEffect to respect your state hook, put setExperienceData inside the dependency array
const [experienceData, setExperienceData] = useState([]);
const { match = {} } = props;
useEffect(() => {
fetchData();
}, [props.match.params]);
const async fetchData = () => {
if (Object.keys(match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData([...response])
}
}
Could you please try passing [match.params] as the second argument to your useEffect.

Resources