'Why when using setState(...) is the console.log null?
Why when I console.log(data) is does it log the data but when I try and log the item set by set state its null? I don't understand is it because it doesn't have time to update before console logging?
const [currentUser, setCurrentUser] = useState(null);
const [pending, setpending] = useState(true);
const [userData, setuserData] = useState({});
useEffect(() => {
Authentication.auth().onAuthStateChanged((user) => {
setCurrentUser(user)
setpending(false)
localStorage.setItem('user', user.uid);
console.log(localStorage.getItem('user'));
});
getData()
}, []);
const getData = () => {
Authentication.firestore().collection('Health_data')
.doc(localStorage.getItem('user'))
.get()
.then(doc => {
const data = doc.data();
localStorage.setItem('user_data', JSON.stringify(data));
setuserData(data)
console.log(data)
}).catch(function (error) {
console.error("Error reading health", error);
});
console.log(userData)
}
Solution 1:[1]
I'm going to assume you're confused by the output of console.log(userData); at the end of getData. There are two reasons why it doesn't show the updated user, either of which would be enough on its own. :-) They are:
The
console.log(userData)happens before thesetuserDatacall, because promise callbacks are always asynchronous.userDatais a constant within theExamplefunction call, its value will not change. When the state is changed,Examplewill get called again, and that newuserDataconstant will have the updated user in it. (Note that it doesn't matter whether it's declared withletorconst, it's effectively a constant either way.) Each of those constants exists in an execution context that's tied to the specific call toExamplethe constant was created in. More in Dan Abramov's article A Complete Guide touseEffect(which is about much more thanuseEffect).
Here's a demonstration:
const { useState } = React;
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
let executionContext = 0;
const Example = () => {
const contextNumber = ++executionContext;
const [value, setValue] = useState(0);
const log = msg => console.log(`[${contextNumber}]: ${msg}`);
log(`Example called, value = ${value}`);
const onClick = () => {
log(`onClick`);
delay(800)
.then(() => {
const newValue = Math.floor(Math.random() * 10000);
log(`calling setValue(${newValue})...`);
setValue(newValue);
log(`value is still ${value} (reason #2)`);
});
log(`value is still ${value} (reason #1)`);
};
return (
<div>
{value}
<div>
<input type="button" onClick={onClick} value="Click Me" />
</div>
</div>
);
}
ReactDOM.render(<Example/>, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
Solution 2:[2]
If you are talking about this code:
Authentication.firestore().collection('Health_data')
.doc(localStorage.getItem('user'))
.get()
.then(doc => {
const data = doc.data();
localStorage.setItem('user_data', JSON.stringify(data));
setuserData(data)
console.log(data)
}).catch(function (error) {
console.error("Error reading health", error);
});
console.log(userData)
The problem is
Authentication.firestore().collection('Health_data')
.doc(localStorage.getItem('user'))
.get()
Is async execution, so console.log(userData), sometimes will execute before the Authentication call and the value will be null.
So you need to ensure that the Authentication call has finished
Solution 3:[3]
if(userData !== null) {
console.log(userData)
}
this code seems to work for me but I'm not sure how I can use this to access the information on other pages the same way?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Gonzalo Gras Cantou |
| Solution 3 | lukeet |
