I have the following code. The idea is to create a simple loading for a mock component
const [loading, setLoading] = useState(false)
function mockLoading () {
setLoading(true)
console.log('1', loading)
setTimeout(() => {
setLoading(false)
console.log('2', loading)
}, 3000)
}
useEffect(() => {
mockLoading()
}, []);
But for some reason, setLoading is not working. Console.log 1 and 2 both are false
A couple of things. One issue is that when you set the state, the state does not immediately update. So your first console.log will see the old state. Not only that, but when your effect is called and mockLoading
is called, it will only see the instance of state that existed at the time it was called. So any changes to the variable will never be seen by mockLoading
. This is why effects have dependencies. That way when a dependency updates, you'll see it. But I don't think having a dependency here will help given how your code is structured. I'm not 100% clear on your final goal, but to accomplish what you want based on the code you submitted, you'll want to useRef
instead of useState
. useRef
gives you an object who's value is always current. See:
const loadingRef = useRef(false)
function mockLoading () {
loadingRef.current = true;
console.log('1', loadingRef.current)
setTimeout(() => {
loadingRef.current = false;
console.log('2', loadingRef.current)
}, 3000)
}
useEffect(() => {
mockLoading()
}, []);
Using refs is generally frowned upon unless you absolutely need it. Try to refactor your code to have a dependency on loading
in your useEffect
call. Though keep in mind you may end up with an infinite loop if your mockLoading
always updates loading
when it's called. Try to only update loading
if it's not already set to the value you want. If your end goal is to just update loading
after 3 seconds, try this:
const [loading,setLoading] = useState(false);
useEffect(() => {
setTimeout(() => {
setLoading(true);
},3000);
},[]);
return <span>{loading ? 'Loading is true!' : 'Loading is false!'}</span>;
If you want to inspect the value of loading without rendering it, then you'll need another useEffect
with a dependency on loading
:
const [loading,setLoading] = useState(false);
useEffect(() => {
setTimeout(() => {
setLoading(true);
},3000);
},[]);
useEffect(() => {
console.log(loading);
},[loading]);
return <span>{loading ? 'Loading is true!' : 'Loading is false!'}</span>;
Hope this helps.
Declare your handler
inside useEffect
and log outside
const [loading, setLoading] = useState(false)
useEffect(() => {
function mockLoading () {
setLoading(true)
console.log('1', loading)
setTimeout(() => {
setLoading(false)
console.log('2', loading)
}, 3000)
}
mockLoading()
}, []);
console.log(loading)
Also, you should clean your timeout
on unmount
useEffect(() =>{
const timeout = setTimeout(() =>{}, 0)
return clearTimeout(timeout)
},[])
Setting state in React is async, so you won't see the changes to the state straight after you made them. To track state changes you need to use the effect hook:
const [loading, setLoading] = useState(false);
function mockLoading() {
setLoading(true);
console.log("1", loading);
setTimeout(() => {
setLoading(false);
console.log("2", loading);
}, 3000);
}
useEffect(() => {
mockLoading();
}, []);
// Display the current loading state
useEffect(() => {
console.log("loading", loading);
}, [loading]);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.