setState while looping through an array of props - React ComponentDidUpdate - javascript

I am working on a project and needed to setState after componentDidMount.(The props am expecting in the child component are derived at mount. Hence i can only setState after)
Only option i was able to come up with was, using componentDidUpdate.
The props parent component is an array derived from an axios fetched data.
The goal here is to loop though the array and fetch data for each from the URL showing in the code below to then setState of the child component.
Trying what i normally do, I could not stop the infinite loop fired at componentDidUpdate.
Here is my code.
Parent
render(){
return (
<div className="App">
<EachCountry countryList= {this.state.CountriesList}/>
</div>
Child component
async componentDidUpdate(prevProps, prevState, snapshot){
if(this.state.countryList.length < this.props.countryList.length){
await this.props.countryList.map(m=>{
axios ({
method:"get",
url:`/countryupdate/${m}`
}).then(res=>{
console.log(res.data)
this.setState(crntState=>({
countryList:[...crntState.countryList, res.data]
}))
})
})
}
}
console log works perfectly fine. But when i tried to setState, i run into infinite loop with something like 5000 plus error messages.
And my other trick was
async componentDidUpdate(prevProps, prevState, snapshot){
if(this.state.countryList.length < this.props.countryList.length){
await this.props.countryList.map(m=>{
var newdata = axios ({
method:"get",
url:`/countryupdate/${m}`
})
console.log(newdata)
this.setState(crntState=>({
countryList:[...crntState.countryList, newdata.data]
}))
})
}
}
And this one returns promises and not the needed data.
Help Fam
What am i missing?

Your issue is likely caused by derived state: state that is dependent on props and is an anti pattern in react:
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#when-to-use-derived-state
See below on a plausible workaround, though its recommended you restructure your data flow.
Try something like this to first only send 1 update to state:
async componentDidMount(){
//variable to store new data
const allNewData = [];
//an async data fetcher
const getNewData = async(m) => {
let newData = await axios({
method: "get",
url: `/countryupdate/${m}`
})
allNewData.push(newData.data);
}
//an async for loop
async function updateData() {
for (const m of countryList) {
await getNewData(m);
}
this.setState(crntState => ({
countryList: [...crntState.countryList, ...allNewData]
}))
}
await updateData();
}
If the above doesn't work (which it might not), then use getDerivedStateFromProps instead of componentDidMount and replace setState with a return obj
static getDerivedStateFromProps(props, state) {
if (this.state.countryList.length < this.props.countryList.length) {
...
return {
countryList: [...state.countryList, ...allNewData]
};
}
let newState = await updateData();
return newState;
}
If that doesn't work, then revert back to componentDidMount and use shouldComponentUpdate for the conditional
shouldComponentUpdate(nextProps, nextState) {
return this.state.countryList.length != nextState.countryList.length;
}
Incase I didn't get the syntax just right look at this code snippet
function mockAxios(m) {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve({
data: `${m}'s data`
}), 1000)
});
}
function setState(arr) {
console.log(arr);
console.log("state has been set")
}
const countryList = ["A", "B", "C", "D", "E"];
///////////////////////////////////////////////
async function componentDidMount() {
const allNewData = [];
async function getNewData(m) {
let newData = await mockAxios(m);
allNewData.push(newData.data);
}
async function updateData() {
for (const m of countryList) {
await getNewData(m);
console.log("fetching data...")
}
setState(allNewData);
}
await updateData();
}
componentDidMount();

Related

useEffect must not return anything beside a function, which is used for clean-up Error Comes up Every Screen [duplicate]

I was trying the useEffect example something like below:
useEffect(async () => {
try {
const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
}, []);
and I get this warning in my console. But the cleanup is optional for async calls I think. I am not sure why I get this warning. Linking sandbox for examples. https://codesandbox.io/s/24rj871r0p
For React version <=17
I suggest to look at Dan Abramov (one of the React core maintainers) answer here:
I think you're making it more complicated than it needs to be.
function Example() {
const [data, dataSet] = useState<any>(null)
useEffect(() => {
async function fetchMyAPI() {
let response = await fetch('api/data')
response = await response.json()
dataSet(response)
}
fetchMyAPI()
}, [])
return <div>{JSON.stringify(data)}</div>
}
Longer term we'll discourage this pattern because it encourages race conditions. Such as — anything could happen between your call starts and ends, and you could have gotten new props. Instead, we'll recommend Suspense for data fetching which will look more like
const response = MyAPIResource.read();
and no effects. But in the meantime you can move the async stuff to a separate function and call it.
You can read more about experimental suspense here.
If you want to use functions outside with eslint.
function OutsideUsageExample({ userId }) {
const [data, dataSet] = useState<any>(null)
const fetchMyAPI = useCallback(async () => {
let response = await fetch('api/data/' + userId)
response = await response.json()
dataSet(response)
}, [userId]) // if userId changes, useEffect will run again
useEffect(() => {
fetchMyAPI()
}, [fetchMyAPI])
return (
<div>
<div>data: {JSON.stringify(data)}</div>
<div>
<button onClick={fetchMyAPI}>manual fetch</button>
</div>
</div>
)
}
For React version >=18
Starting with React 18 you can also use Suspense, but it's not yet recommended if you are not using frameworks that correctly implement it:
In React 18, you can start using Suspense for data fetching in opinionated frameworks like Relay, Next.js, Hydrogen, or Remix. Ad hoc data fetching with Suspense is technically possible, but still not recommended as a general strategy.
If not part of the framework, you can try some libs that implement it like swr.
Oversimplified example of how suspense works. You need to throw a promise for Suspense to catch it, show fallback component first and render Main component when promise it's resolved.
let fullfilled = false;
let promise;
const fetchData = () => {
if (!fullfilled) {
if (!promise) {
promise = new Promise(async (resolve) => {
const res = await fetch('api/data')
const data = await res.json()
fullfilled = true
resolve(data)
});
}
throw promise
}
};
const Main = () => {
fetchData();
return <div>Loaded</div>;
};
const App = () => (
<Suspense fallback={"Loading..."}>
<Main />
</Suspense>
);
When you use an async function like
async () => {
try {
const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
}
it returns a promise and useEffect doesn't expect the callback function to return Promise, rather it expects that nothing is returned or a function is returned.
As a workaround for the warning you can use a self invoking async function.
useEffect(() => {
(async function() {
try {
const response = await fetch(
`https://www.reddit.com/r/${subreddit}.json`
);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
})();
}, []);
or to make it more cleaner you could define a function and then call it
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(
`https://www.reddit.com/r/${subreddit}.json`
);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
};
fetchData();
}, []);
the second solution will make it easier to read and will help you write code to cancel previous requests if a new one is fired or save the latest request response in state
Working codesandbox
Until React provides a better way, you can create a helper, useEffectAsync.js:
import { useEffect } from 'react';
export default function useEffectAsync(effect, inputs) {
useEffect(() => {
effect();
}, inputs);
}
Now you can pass an async function:
useEffectAsync(async () => {
const items = await fetchSomeItems();
console.log(items);
}, []);
Update
If you choose this approach, note that it's bad form. I resort to this when I know it's safe, but it's always bad form and haphazard.
Suspense for Data Fetching, which is still experimental, will solve some of the cases.
In other cases, you can model the async results as events so that you can add or remove a listener based on the component life cycle.
Or you can model the async results as an Observable so that you can subscribe and unsubscribe based on the component life cycle.
You can also use IIFE format as well to keep things short
function Example() {
const [data, dataSet] = useState<any>(null)
useEffect(() => {
(async () => {
let response = await fetch('api/data')
response = await response.json()
dataSet(response);
})();
}, [])
return <div>{JSON.stringify(data)}</div>
}
void operator could be used here.
Instead of:
React.useEffect(() => {
async function fetchData() {
}
fetchData();
}, []);
or
React.useEffect(() => {
(async function fetchData() {
})()
}, []);
you could write:
React.useEffect(() => {
void async function fetchData() {
}();
}, []);
It is a little bit cleaner and prettier.
Async effects could cause memory leaks so it is important to perform cleanup on component unmount. In case of fetch this could look like this:
function App() {
const [ data, setData ] = React.useState([]);
React.useEffect(() => {
const abortController = new AbortController();
void async function fetchData() {
try {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
const response = await fetch(url, { signal: abortController.signal });
setData(await response.json());
} catch (error) {
console.log('error', error);
}
}();
return () => {
abortController.abort(); // cancel pending fetch request on component unmount
};
}, []);
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
I read through this question, and feel the best way to implement useEffect is not mentioned in the answers.
Let's say you have a network call, and would like to do something once you have the response.
For the sake of simplicity, let's store the network response in a state variable.
One might want to use action/reducer to update the store with the network response.
const [data, setData] = useState(null);
/* This would be called on initial page load */
useEffect(()=>{
fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then(data => {
setData(data);
})
.catch(err => {
/* perform error handling if desired */
});
}, [])
/* This would be called when store/state data is updated */
useEffect(()=>{
if (data) {
setPosts(data.children.map(it => {
/* do what you want */
}));
}
}, [data]);
Reference => https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
For other readers, the error can come from the fact that there is no brackets wrapping the async function:
Considering the async function initData
async function initData() {
}
This code will lead to your error:
useEffect(() => initData(), []);
But this one, won't:
useEffect(() => { initData(); }, []);
(Notice the brackets around initData()
For fetching from an external API using React Hooks, you should call a function that fetches from the API inside of the useEffect hook.
Like this:
async function fetchData() {
const res = await fetch("https://swapi.co/api/planets/4/");
res
.json()
.then(res => setPosts(res))
.catch(err => setErrors(err));
}
useEffect(() => {
fetchData();
}, []);
I strongly recommend that you do not define your query inside the useEffect Hook, because it will be re-render infinite times. And since you cannot make the useEffect async, you can make the function inside of it to be async.
In the example shown above, the API call is in another separated async function so it makes sure that the call is async and that it only happens once. Also, the useEffect's dependency array (the []) is empty, which means that it will behave just like the componentDidMount from React Class Components, it will only be executed once when the component is mounted.
For the loading text, you can use React's conditional rendering to validate if your posts are null, if they are, render a loading text, else, show the posts. The else will be true when you finish fetching data from the API and the posts are not null.
{posts === null ? <p> Loading... </p>
: posts.map((post) => (
<Link key={post._id} to={`/blog/${post.slug.current}`}>
<img src={post.mainImage.asset.url} alt={post.mainImage.alt} />
<h2>{post.title}</h2>
</Link>
))}
I see you already are using conditional rendering so I recommend you dive more into it, especially for validating if an object is null or not!
I recommend you read the following articles in case you need more information about consuming an API using Hooks.
https://betterprogramming.pub/how-to-fetch-data-from-an-api-with-react-hooks-9e7202b8afcd
https://reactjs.org/docs/conditional-rendering.html
try
const MyFunctionnalComponent: React.FC = props => {
useEffect(() => {
// Using an IIFE
(async function anyNameFunction() {
await loadContent();
})();
}, []);
return <div></div>;
};
Other answers have been given by many examples and are clearly explained, so I will explain them from the point of view of TypeScript type definition.
The useEffect hook TypeScript signature:
function useEffect(effect: EffectCallback, deps?: DependencyList): void;
The type of effect:
// NOTE: callbacks are _only_ allowed to return either void, or a destructor.
type EffectCallback = () => (void | Destructor);
// Destructors are only allowed to return void.
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };
Now we should know why effect can't be an async function.
useEffect(async () => {
//...
}, [])
The async function will return a JS promise with an implicit undefined value. This is not the expectation of useEffect.
Please try this
useEffect(() => {
(async () => {
const products = await api.index()
setFilteredProducts(products)
setProducts(products)
})()
}, [])
To do it properly and avoid errors: "Warning: Can't perform a React state update on an unmounted..."
useEffect(() => {
let mounted = true;
(async () => {
try {
const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
const json = await response.json();
const newPosts = json.data.children.map(it => it.data);
if (mounted) {
setPosts(newPosts);
}
} catch (e) {
console.error(e);
}
})();
return () => {
mounted = false;
};
}, []);
OR External functions and using an object
useEffect(() => {
let status = { mounted: true };
query(status);
return () => {
status.mounted = false;
};
}, []);
const query = async (status: { mounted: boolean }) => {
try {
const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
const json = await response.json();
const newPosts = json.data.children.map(it => it.data);
if (status.mounted) {
setPosts(newPosts);
}
} catch (e) {
console.error(e);
}
};
OR AbortController
useEffect(() => {
const abortController = new AbortController();
(async () => {
try {
const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`, { signal: abortController.signal });
const json = await response.json();
const newPosts = json.data.children.map(it => it.data);
setPosts(newPosts);
} catch (e) {
if(!abortController.signal.aborted){
console.error(e);
}
}
})();
return () => {
abortController.abort();
};
}, []);
I know it is late but just I had the same problem and I wanted to share that I solved it with a function like this!
useEffect(() => {
(async () => {
try {
const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
}) ()
}, [])
With useAsyncEffect hook provided by a custom library, safely execution of async code and making requests inside effects become trivially since it makes your code auto-cancellable (this is just one thing from the feature list). Check out the Live Demo with JSON fetching
import React from "react";
import { useAsyncEffect } from "use-async-effect2";
import cpFetch from "cp-fetch";
/*
Notice: the related network request will also be aborted
Checkout your network console
*/
function TestComponent(props) {
const [cancel, done, result, err] = useAsyncEffect(
function* () {
const response = yield cpFetch(props.url).timeout(props.timeout);
return yield response.json();
},
{ states: true, deps: [props.url] }
);
return (
<div className="component">
<div className="caption">useAsyncEffect demo:</div>
<div>
{done ? (err ? err.toString() : JSON.stringify(result)) : "loading..."}
</div>
<button className="btn btn-warning" onClick={cancel} disabled={done}>
Cancel async effect
</button>
</div>
);
}
export default TestComponent;
The same demo using axios
Just a note about HOW AWESOME the purescript language handles this problem of stale effects with Aff monad
WITHOUT PURESCRIPT
you have to use AbortController
function App() {
const [ data, setData ] = React.useState([]);
React.useEffect(() => {
const abortController = new AbortController();
void async function fetchData() {
try {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
const response = await fetch(url, { signal: abortController.signal });
setData(await response.json());
} catch (error) {
console.log('error', error);
}
}();
return () => {
abortController.abort(); // cancel pending fetch request on component unmount
};
}, []);
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
or stale (from NoahZinsmeister/web3-react example)
function Balance() {
const { account, library, chainId } = useWeb3React()
const [balance, setBalance] = React.useState()
React.useEffect((): any => {
if (!!account && !!library) {
let stale = false
library
.getBalance(account)
.then((balance: any) => {
if (!stale) {
setBalance(balance)
}
})
.catch(() => {
if (!stale) {
setBalance(null)
}
})
return () => { // NOTE: will be called every time deps changes
stale = true
setBalance(undefined)
}
}
}, [account, library, chainId]) // ensures refresh if referential identity of library doesn't change across chainIds
...
WITH PURESCRIPT
check how useAff kills it's Aff in the cleanup function
the Aff is implemented as a state machine (without promises)
but what is relevant to us here is that:
the Aff encodes how to stop the Aff - You can put your AbortController here
it will STOP running Effects (not tested) and Affs (it will not run then from the second example, so it will NOT setBalance(balance)) IF the error was thrown TO the fiber OR INSIDE the fiber
Ignore the warning, and use the useEffect hook with an async function like this:
import { useEffect, useState } from "react";
function MyComponent({ objId }) {
const [data, setData] = useState();
useEffect(() => {
if (objId === null || objId === undefined) {
return;
}
async function retrieveObjectData() {
const response = await fetch(`path/to/api/objects/${objId}/`);
const jsonData = response.json();
setData(jsonData);
}
retrieveObjectData();
}, [objId]);
if (objId === null || objId === undefined) {
return (<span>Object ID needs to be set</span>);
}
if (data) {
return (<span>Object ID is {objId}, data is {data}</span>);
}
return (<span>Loading...</span>);
}
The most easy way is to use useAsyncEffect from 'use-async-effect'
You can find it on NPM.
const ProtectedRoute = ({ children }) => {
const [isAuth, setIsAuth] = useState(false);
useAsyncEffect(async () => {
try {
const data = await axios("auth");
console.log(data);
setIsAuth(true);
} catch (error) {
console.log(error);
}
}, []);
if (!isAuth)
return <Navigate to="/signin" />
return children;
}

React: How to properly set state at first load

I have this function that gets some initial data in db:
private getFilter() {
let getResp;
let defaultselected = [];
axios.get(getEndPoint)
.then(response => {
getResp = response.data;
defaultselected = JSON.parse(getResp['JsonValue']);
this.setState({ customFilter: defaultselected});
})
}
And this function that loads data from db also:
getOpenClaims = (pageNumber: number) => {
console.log('getOpenClaims', this.state.customFilter)
//logic here
}
on first load, this.state.customFilter is undefined but if I getOpenClaims is executed again by other way, this.state.customFilter has already it's expected value and I already validated that getFilter has a return data from console.log
And here is how I called both functions:
async componentDidMount() {
document.title = "Claim Aging";
this.getOpenClaims(1);
}
componentWillMount() {
this.getFilter();
}
What Am I missing here?
You need to wait for execution of getFilter()before calling getOpenClaims
A little refactoring can help
private async getFilter() { // made this function a promise, using async/await
let getResp;
let defaultselected = [];
const response = await axios.get(getEndPoint)
getResp = response.data;
defaultselected = JSON.parse(getResp['JsonValue']);
this.setState({ customFilter: defaultselected});
}
async componentDidMount() {
document.title = "Claim Aging";
await this.getFilter(); // wait for promise to resolve and then call `getOpenClaims`
this.getOpenClaims(1);
}
constructor(props) {
super(props);
this.state = {
customFilter: value
}
}
You can define the state in the constructor.

Async function call repeated inside of class component

I've created an Asynchronous function to call a weather API that will return the requested information submitted. The function works fine however when I call this function inside of a Class Component the result is returned twice. This isn't exactly a breaking bug but I'd rather not have two API calls occurring if not necessary and I'm curious as to why this method is being called twice in the first place.
Here is my code.
async function submitQuery(props) {
//Incase I decide to add aditional parameters such as city, country etc.. I've decided to place the zip property in an object so I can just
//add additional properties in the submissions object
const submission = {
zip: props,
};
if (!Number(props)) return console.log("this is not a number");
const { error } = await validate(submission);
if (error) return console.log(error.message);
const config = {
method: "get",
url: `https://api.openweathermap.org/data/2.5/weather?zip=${props}&appid=${apiKey}`,
headers: {},
};
/*
const query = await axios(config).then(function (response) {
const result = response.data.main;
return result;
});
*/
//console.log(query);
return 4;
}
class WeatherReport extends React.Component {
getResults = async () => {
const result = await submitQuery("08060");
console.log(result);
};
render() {
return (
<div className="reportContainer">
<WeatherCard getResults={this.getResults} />
</div>
);
}
}
const WeatherCard = ({ getResults }) => {
getResults();
return <div></div>;
};
The problem is that you're calling getResults in the render method of WeatherCard, move it to a useEffect so its not called every time
const WeatherCard = ({ getResults }) => {
React.useEffect(() => {
getResults();
}, [getResults]);
return <div></div>;
};

How to get the return value of a async function that returns a promise

So I have a code like this
const getAllProduct = async () => {
let allProduct = "";
let config = {
method: "get",
url: db_base_url + "/products/",
headers: {
Authorization: "Bearer " + token.access.token,
"Content-Type": "application/json",
},
};
try {
let response = await axios(config);
allProduct = response.data.results;
} catch (error) {
console.log(error);
}
console.log(allProduct);
return allProduct;
};
The console.log(allProduct) do prints an array.
The function will be called on the render method of react by
return (<div> {getAllProduct()} </div>)
I've tried to do
return (<div> {console.log(getAllProduct())} </div>
But the console.log on rendering returns to be Promise Object instead of the results array.
How can I go around this?
async functions return a Promise which means their result is not immediately available.
What you need to do is either await the result of calling getAllProduct() function or chain a then() method call.
Looking at your code, i assume that you want to call getAllProduct() function after after your component is rendered. If that's the case, useEffect() hook is where you should call your function.
You could define and call your function inside the useEffect() hook and once the data is available, save that in the local state your component.
First define the local state of the component
const [products, setProducts] = useState([]);
Define and call the getAllProduct() function inside the useEffect() hook.
useEffect(() => {
const getAllProduct = async () => {
...
try {
let response = await axios(config);
allProduct = response.data.results;
// save the data in the state
setProducts(allProduct);
} catch (error) {
console.log(error);
}
};
// call your async function
getAllProduct();
}, []);
Finally, inside the JSX, .map() over the products array and render the products in whatever way you want to render in the DOM.
return (
<div>
{ products.map(prod => {
// return some JSX with the appropriate data
}) }
</div>
);
use
getAllProduct().then(res => console.log(res))
async function always return a promise you use await before call it getAllProduct()
const res = await getAllProduct();
console.log(res)
In my case daisy chaining .then didn't work. Possibly due to fact that I had a helper JS file that held all DB related functions and their data was utilized across various React components.
What did work was daisy chaining await within an async. I modified code where it works for same Component (like in your case). But we can take same logic , put async function in different JS file and use its response in some other component.
Disclaimer : I haven't tested below code as my case was different.
useEffect( () => {
var handleError = function (err) {
console.warn(err);
return new Response(JSON.stringify({
code: 400,
message: 'Error in axios query execution'
}));
};
const getAllProduct = async () => {
let allProduct = "";
...
const response = await ( axios(config).catch(handleError));
allProduct = await response;
return allProduct;
}
},[]);
// Then inside JSX return
getAllProduct().then( data => {
// Make use of data
});

React.js useEffect with nested async functions

I have the common warning displaying upon loading of my web app but never again...
Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in a useEffect
cleanup function.
EDIT****
It is caused by this chunk of code. I have narrowed it down to one function. It blows up when I try to setMoisture state. I am not sure why.
function getData (){
Axios.get("http://localhost:3001/api/get-value").then((response) => {
const recievedData = response.data;
const dataValue = recievedData.map((val) => {
return [val.value]
})
if (loading === true){
setLoading(false);
}
return parseInt(dataValue);
}).then((resp)=>setMoisture(resp))
}
React.useEffect(() => {
if (moisture === "initialState"){
getData();
}
}, []);
Posting the answer here (based from the comments) for completeness.
Basically, use local variables and cleanup function towards the end of useEffect(). Using this as reference:
Similar situation here
You should declare the function inside the useEffect or add it as a dependency. one way to do it's just moving your function inside the hook.
// I assumed that your useState hooks looks something similar.
const [moisture, setMoisture] = React.useState('initialState')
const [loading, setLoading] = React.useState(true)
React.useEffect(() => {
function getData() {
Axios.get("http://localhost:3001/api/get-value").then((response) => {
const recievedData = response.data;
const dataValue = recievedData.map((val) => {
return [val.value]
})
if(loading === true) {
setLoading(false);
}
return parseInt(dataValue);
}).then((resp => setMoisture(resp)))
}
if (moisture === "initialState"){
getData();
}
}, [])
You also probably want to first set your data to the state and then change your loading state to false, this is gonna prevent some bugs. This is another way to do it and manage the loading state and the promises
React.useEffect(() => {
function getData() {
setLoading(true)
Axios.get("http://localhost:3001/api/get-value")
.then((response) => {
const dataValue = response.data.map((val) => {
return [val.value]
})
// This is going to pass 0 when can't parse the data
setMoisture(parseInt(dataValue) || 0)
setLoading(false)
})
}
getData()
}, [])

Categories