Get data from async function and update state - reactjs

I have created a variable using useState and that is an empty array.
const [data, setData] = useState([]);
I am calling an async function inside useEffect that is helping me to get all the data and update the data when received
useEffect(() => {
//
const items = [];
async function fetchData() {
items = await getAllItems(); //it should wait for data and then setData
setData(items);
}
fetchData();
console.log("from useEffect", items); // still items array is empty
}, []);
Here is my imported data retrieving function which uses Axios and returns the data:
export const getAllItems = async () => {
const url = baseUrl + "/items/getAllItems";
await axios({
method: "GET",
withCredentials: true,
url: url,
}).then((res) => {
return res; // when console logged we get a proper array if data
});
};
But nothing works all I am getting back is object of promise. Could anyone guide me what I am missing out in my code?

You are assigning the value of getAllItems() to a constant variable items that has already been declared here:
const items = [];
However, as per the mdn web docs:
The value of a constant can't be changed through reassignment (i.e. by using the assignment operator), and it can't be redeclared (i.e. through a variable declaration).
So you need to either initialize that variable using let, or better yet assign it immediately as follow:
const items = await getAllItems();
You can then get rid of const items = [];

You didn't return the data from the axios call.
export const getAllItems = async () => {
const url = baseUrl + "/items/getAllItems";
const { data } = await axios({
method: "GET",
withCredentials: true,
url: url,
});
return data;
};

Your console.log() is in the wrong position (2). Should be in the position marked with (1) instead. Please check the comments I added:
useEffect(() => {
const items = [];
async function fetchData() {
items = await getAllItems(); //it should wait for data and then setData
setData(items);
// (1) you chould console.log() the items array here instead
// if the data is properly returned from getAllItems() it will be visible here
console.log("from useEffect", items);
}
fetchData();
console.log("from useEffect", items); // (2) items array will be empty here right after fetchData() as getAllItems() has not returned yet.
}, []);

useEffect(() => {
let isMounted = true
function fetchData() {
const items = axios.get(baseUrl + "/items/getAllItems")
if (isMounted) setData(items);
}
fetchData();
return () => {isMounted = false}
}, []);

Related

How can I use the results of an async function inside useEffect?

I am dispatching an async function inside my useEffect:
let carts = [];
useEffect(() => {
dispatch(getOrder(orderID));
}, []);
here is my function
export const getOrders = createAsyncThunk("cart/getorders", async () => {
const response = await axios.get("http://127.0.0.1:8000/techcart/orders/", {
headers: {
Authorization: `Token ${token}`,
},
});
return response.data;
});
I want to use the results of this function and put it an array
order.cart.forEach((element) => {
carts.push(element);
});
how can i do it after useffect has finished ?
i tried putting it a function inside use effect but it gave the same error
cart.foreach is not a function
anyone can help me?
I'm unsure whether you want this to actually happen inside the useEffect. If you wish to preserve the result of your api call in a state variable, you can declare:
const [orders, setOrders] = useState<Order[]>([]);
Then, wrap the getOrder method:
const getOrderWrapper = async (orderId: string) => {
const orders = await getOrder(orderId);
setOrders(orders.cart);
}
Then, in your useEffect, you can add the following:
useEffect(() => {
dispatch(getOrderWrapper(getOrder(orderID)));
}, []);
If you need to run async code inside useEffect, you can do it like this
useEffect(() => {
(async () => {
const response = await dispatch(....)
})();
}, [])

ReactJS: Wait for data before saving to useState [duplicate]

This question already has answers here:
React Hooks: how to wait for the data to be fetched before rendering
(4 answers)
Closed 1 year ago.
i have the following problem:
I'm fetching data (true or false value) from my database and want to save it to a useState.
I'm using async/await for the fetch. Because of that, the value saved to my state is undefined.
Here is my code:
const [myState, setMyState] = useState();
useEffect(() => {
myFunction()
async function myFunction () {
const req = await fetch("http://localhost:3001/api/getdata", {
headers: {
"x-access-token": sessionStorage.getItem("token")
}
})
const data = await req.json()
console.log("fetched data value: " + data)
// This is undefined in the console
setMyState(data)
// I already tried this, but await does not affect a setState
// const blah = await setMyState(data)
}
}, [])
How can i wait for the data to be fetched before saving it to the state?
Thanks for helping.
Since you have an async function, you can use then() promise handlers to only set the state once the data is fetched. Here's an example:
const [myState, setMyState] = useState();
useEffect(() => {
myFunction()
async function myFunction () {
// Call then() after using fetch to pass the result into a callback that saves state
fetch("http://localhost:3001/api/getdata", {
headers: {
"x-access-token": sessionStorage.getItem("token")
}
}).then(
(response) => response.json()
).then(
(data) => setMyState(data)
)
}
}, [])
Check out the official web api for fetch: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
What you have should work but you should set an initial value for your useState to an empty array or what ever it is your data will eventually be or at least null or undefined explicitly that way you know what state it is before its loaded
Below is stackblitz with a working example
https://stackblitz.com/edit/react-pimpje?file=src/App.js
function App() {
const [myState, setMyState] = React.useState(null);
React.useEffect(() => {
async function myFunction() {
/**
* https://apipheny.io/free-api/
*/
const req = await fetch('https://api.publicapis.org/entries');
const data = await req.json();
console.log('fetched data value: ', data);
setMyState(data);
}
myFunction();
}, []);
return <div>{myState && <pre>{JSON.stringify(myState, null, 2)}</pre>}</div>;
}

React Native - I want to set my session state first before I call my API

I am new to React Native.
If someone can help me then would be great.
How I can set my session state first from AsyncStorage before it goes for API call. Because this API call required sessionId (UserId) so it can return only those data which belong to this userId.
The issue I am currently facing is when API calls for the data it is calling with null seesionId instead of some value which I am getting from AsyncStorage because both methods (settingSession, InitList ) are async.
const [sessionId, setSessionId] = useState(null);
const settingSession = async () => {
await AsyncStorage.getItem('userId').then(val => setSessionId(val));
}
useEffect(() => {
settingSession(); // Setting sessionId
InitList(); // Calling API which required session value
}, []);
const InitList = async () => {
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
try {
// getting sessionId null instead of value from AsyncStorage
const response = await fetch("http://127.0.0.1:8080/skyzerguide/referenceGuideFunctions/tetra/user/" + sessionId, requestOptions)
const status = await response.status;
const responseJson = await response.json();
if (status == 204) {
throw new Error('204 - No Content');
} else {
setMasterDataSource(responseJson);
}
} catch (error) {
console.log(error);
return false;
}
}
I'm thinking of two possible solutions:
Separate InitList() into a separate useEffect call, and put sessionId in the dependency array, so that the API call is only made when the sessionId has actually been updated:
useEffect(() => {
settingSession(); // Setting sessionId
}, []);
useEffect(() => {
InitList(); // Calling API which required session value
}, [sessionId]);
Wrap both functions in an async function within the useEffect call, and call them sequentially using await:
useEffect(() => {
const setSessionAndInitList = async() => {
await InitList(); // Calling API which required session value
await settingSession(); // Setting sessionId
}
setSessionAndInitList()
}, []);
Let me know if either works!

Data cannot be assigned to state in interval function in useEffect

Im getting data from axios async function and trying to assign to state in same function. When I print the values on console, i see that temporary value is not null but state is always null. when i rerender the page, state is not being null.
const [Pickup, setPickUp] = useState([]);
async function GetOrders() {
const result = await axios(
`EXAMPLEURL`,
);
setOrders(result.data);
var temp = [];
result.data.allOrders.forEach(element => {
if (element.order_type === 'PickupOrders') {
temp.push(element);
}
});
console.log(temp);
if (Pickup !== temp) {
setPickUp(temp);
}
}
useEffect(() => {
GetOrders();
const interval = setInterval(() => {
GetOrders();
console.log(Pickup);
}, 1000 * 5);
return () => clearInterval(interval)
}, []);
On console:
How can i fix this problem?
I assume you want to make a get request. Your axios function need to be completed such as ;
await axios
.get("YOUR URL", {
headers: // if you need to add header,
})
.then((response) =>{
setOrders(reponse.data);
})
.catch((error) => {
result = { errorMessage: error.message };
console.error('There was an error!', error);
});
return result;
Not completely sure what you're trying to achieve, but you can't compare Pickup !== temp this will be false all the time, you're comparing object references. Js will return all the time those values aren't equal.
This function GetOrders return a promise you don't need to use interval, you can use GetOrders.then(lambdaFunctionHere -> ());

React - How do I get fetched data outside of an async function?

I'm trying to get the data of "body" outside of the fetchUserData() function.
I just want to store it in an variable for later use.
Also tried modifying state, but didn't work either.
Thanks for your help :)
const [userData, setUserData] = useState();
async function fetchUserData () {
try {
const result = await fetch(`/usermanagement/getdocent`, {
method: "GET"
});
const body = await result.json();
//setUserData(body);
return(
body
)
} catch (err) {
console.log(err);
}
}
let userTestData
fetchUserData().then(data => {userTestData = data});
console.log(userTestData);
//console.log(userData);
Use useEffect
async function fetchUserData () {
try {
const result = await fetch(`/usermanagement/getdocent`, {
method: "GET"
})
return await result.json()
} catch (err) {
console.log(err)
return null
}
}
const FunctionalComponent = () => {
const [userData, setUserData] = useState()
useEffect(() => {
fetchUserData().then(data => {
data && setUserData(data)
})
}, []) // componentDidMount
return <div />
}
Ben Awad's awesome tutorial
Example:
it seems that you are making it more complicated than it should be. When you get the response i.e the resolved promise with the data inside the async function, just set the state and in the next render you should get the updated data.
Example:
const [userData, setUserData] = useState();
useEffect(() => {
const getResponse = async () => {
try {
const result = await fetch(`/usermanagement/getdocent`, {
method: "GET"
});
const body = await result.json();
setUserData(body);
} catch (err) {
console.log(err)
}
}
getResponse();
}, [])
console.log(userData);
return <div></div>
Assuming the you need to call the function only once define and call it inside a useEffect or 'componentDidMount'. For using async function inside useEffect we need to define another function and then call it.
When you do
let userTestData
// This line does not wait and next line is executed immediately before userTestData is set
fetchUserData().then(data => {userTestData = data});
console.log(userTestData);
// Try changing to
async someAsyncScope() {
const userTestData = await fetchUserData();
console.log(userTestData)
}
Example:
state = {
someKey: 'someInitialValue'
};
async myAsyncMethod() {
const myAsyncValue = await anotherAsyncMethod();
this.setState({ someKey: myAsyncValue });
}
/*
* Then in the template or where ever, use a state variable which you update when
* the promise resolves. When a state value is used, once the state is updated,
* it triggers as a re-render
*/
render() {
return <div>{this.state.someKey}</div>;
}
In your example you'd use setUserData instead of this.setState and userData instead of {this.state.someKey}

Resources