Object outside of Promise is empty [duplicate] - reactjs

This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed 1 year ago.
I receive the data for the user object by an api call. Inside the getSelectedUser function, the console.log returns the filled user object. But in the console.log in the useEffect returns an empty object. What am I doing wrong?
Foo.tsx
const [user, setUser] = useState<IUser>(initialUser);
useEffect(() => {
getSelectedUser();
console.log(user);
}, []);
async function getSelectedUser() {
await getUserById(userId).then((data) => {
setUser(data);
console.log(data);
});
}
Service.tsx
export const getUserById = async (userId: string | number) => {
const user = ...;
const token = ...;
try {
const response = await fetch(`${apiurl}/${userId}`, {
method: 'GET',
...
}).then((res) => res.json());
return response;
} catch (error) {
console.log(error);
}
};

Because state only has new value when component re-render. So you can put console.log(user); out side the useEffect to check like this:
useEffect(() => {
getSelectedUser();
}, []);
console.log(user);
Or you can use other useEffect with dependencies to check the value of new state when compoent re-render
useEffect (() => {
console.log(user);
}, [user])

Related

why is my state not updated in useEffect?

const user = useSelector(state => state.user)
const [gioHangChiTiet, setGioHangChiTiet] = useState([])
const [gioHangSanPham, setGioHangSanPham] = useState([])
useEffect(() => {
const dataGioHang = async () => {
try {
const res = await axios.get(`${apiUrl}api/giohangs`, {
headers: {
token: `Bearer ${user.user?.accessToken}`
}
})
console.log(res.data.data.sach)
setGioHangChiTiet(res.data.data)
console.log(gioHangChiTiet "it is empty")
} catch (error) {
console.log(error)
}
}
if (user.user) {
dataGioHang()
// console.log(gioHangChiTiet)
}
}, [user])
That is my code. I trying to save gioHangChiTiet with new data but it's always is an empty array. I try console.log this and I think it will work but it's not. But if I change any thing in this code, gioHangChiTiet will update new data and console.log this. Can anyone help me and explain why? Thank you so much. I spent a lot of time figuring out how to solve it :(( . UPDATED : I fixed it. Thanks a lots ( console.log not run because it in useEffect , if i console after useEffect, i will have true value)
const user = useSelector(state => state.user)
const [gioHangChiTiet, setGioHangChiTiet] = useState([])
const [gioHangSanPham, setGioHangSanPham] = useState([])
useEffect(() => {
const dataGioHang = async () => {
try {
const res = await axios.get(`${apiUrl}api/giohangs`, {
headers: {
token: `Bearer ${user.user?.accessToken}`
}
})
console.log(res.data.data.sach)
// setGioHangChiTiet(res.data.data.sach)
setGioHangChiTiet(res.data.data)
console.log(gioHangChiTiet)
} catch (error) {
console.log(error)
}
}
if (user.user) {
dataGioHang()
// console.log(gioHangChiTiet)
}
}, [user])
Add user to your dependency array. Otherwise the useEffect wont be able to check your if statement. If you're using CRA you should get a warning in your terminal.
useEffect takes two arguments first one is callback function and second one is dependency array.
useEffect(() => {
// this is callback function
},[ /* this is dependency array */ ])
If you want to trigger the callback function every time a state changes you need to pass that state in dependency array.
useEffect(() => {
console.log(someState)
},[someState])
In above code someState will get logged each time it's value changes.
If your dependency array is empty you useEffect callback function will trigger ONLY ONCE.
In your case if you want trigger callback function on change of user state or any other state simply pass it in dependency array.
Can you give this a try:
const user = useSelector(state => state.user)
const [gioHangChiTiet, setGioHangChiTiet] = useState([])
const [gioHangSanPham, setGioHangSanPham] = useState([])
useEffect(() => {
const dataGioHang = new Promise((resolve,reject) => {
( async() => {
try {
const res = await axios.get(`${apiUrl}api/giohangs`, {
headers: {
token: `Bearer ${user.user?.accessToken}`
}
})
console.log(res.data.data.sach)
setGioHangChiTiet(res.data.data.sach)
setGioHangChiTiet(res.data.data)
console.log(gioHangChiTiet)
resolve();
} catch (error) {
console.log(error)
reject()
}})();
})
if (user.user) {
dataGioHang().then(()={ console.log(gioHangChiTiet);
})
.catch(() => console.log("Error executing dataGioHang"))
}
}, [user])

Can't fetch data with Axios and React, getting an Promise and Undefined

I'm trying to fetch some data with Axios and React, But I'm having a problem resolving the promise and setting it on the state, that's weird.
Here is the Base:
export const fetchUserById = (username) => client.get(`/${username}`);
Here is the Call:
export const getUserById = async (username) => {
try {
const response = await api.fetchUserById(username);
const data = await response.data;
return data;
} catch (error) {
return error;
}
};
Here is in React:
const [user, setUser] = useState();
useEffect(() => {
const data = getUserById(params.username); // this gets the username and its working
setUser(data)
}, [])
useEffect(() => {
console.log("this is user: ", user)
}, [user])
If I console log user, I get undefined, If I console log data i get a promise.
getUserById is declared async so it implicitly returns a Promise that callers should either await or use a Promise chain on.
useEffect(() => {
const data = getUserById(params.username);
setUser(data); // <-- logs only the returned Promise object!
}, [])
async/await
useEffect(() => {
const getUser = async () => {
try {
const data = await getUserById(params.username);
setUser(data);
} catch(error) {
// handle error, log, etc...
}
};
getUser();
}, []);
Promise chain
useEffect(() => {
getUserById(params.username)
.then(data => {
setUser(data);
})
.catch(error => {
// handle error, log, etc...
});
};
}, []);
Or you could as well do:
useEffect(() => {
// fetch data
(async () => {
try {
const data = await getUserById(params.username);
// set state
setUser(data)
} catch(error) {
// handle error, log, etc...
// set init state
setUser(null)
}
})();
}, []);

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>;
}

Await state loading REACT [duplicate]

This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Async function in react doesn't react to state change
(5 answers)
Closed 1 year ago.
i have a problem to get my state value.
i have declared my state homeworks
const [homeworks, setHomeworks] = useState([])
I call a function in my useEffect
useEffect(()=>{
fetchHomeworks()
},[])
This function call a service for get data from my API. And when data loading i set my states and i load other function with state but i don't get state in my function initMercure()
const fetchHomeworks = async () => {
try {
let data
if (classroom_id === "all") {
data = await homeworksAPI.findAll()
} else {
data = await classroomsAPI.getHomeworks(classroom_id)
}
await setHomeworks(data)
await initMercure()
} catch (error) {
console.log(error)
}
}
const initMercure = async () => {
console.log("homeworks (initMercure): ", homeworks) // <--- HERE, i have array blank []
}
I have try it but don't work
await setHomeworks(data, initMercure())
and
useEffect(()=>{
fetchHomeworks()
initMercure()
},[])
[RESOLVED]
useEffect(()=>{
fetchHomeworks()
fetchClassroom()
},[classroom_id])
useEffect(()=>{
if (homeworks.length>0) initMercure();
},[homeworks])
Thank you <3

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