So, I am making a todolist app and I have this code:
./components/Overlay.js
import { useState } from "react";
function Overlay({Task, SetTask}) {
const [priority, setPriority] = useState('');
const [text, setText] = useState('');
return (
<div className="bg-[#040e16] p-10 rounded-3xl">
<input type="text" className="bg-[#0d1821] mr-3 w-[30rem] h-10 text-lg rounded-lg p-2" value={text} onChange={e => setText(e.target.value)}/>
<button className="bg-[#0d1821] p-2 w-16 rounded-lg hover:bg-[#3b42a4] transition-all" onClick={() => {SetTask({
text: text,
priority: priority
});
console.log(Task)}}>Add</button><br />
<p>Priority: {priority}</p> <br />
<button onClick={() => setPriority('high')}><img src="/hi-priority.png" alt="" className="w-12 hover:bg-[#3b42a4] mr-5 transition-all rounded-2xl"/></button>
<button onClick={() => setPriority('medium')}><img src="/md-priority.png" alt="" className="w-12 hover:bg-[#3b42a4] mr-5 transition-all rounded-2xl"/></button>
<button onClick={() => setPriority('low')}><img src="/lo-priority.png" alt="" className="w-12 hover:bg-[#3b42a4] mr-5 transition-all rounded-2xl"/></button>
</div>
);
}
export default Overlay;
import { useState } from "react";
import NavBar from "../../components/NavBar";
import Overlay from "../../components/Overlay";
function Dashboard() {
const [on, setOn] = useState(false);
const [task, setTask] = useState({
text: "",
priority: "",
})
return (
<div className="">
<NavBar
onClick={() =>{
setOn(!on);
}}
/>
<div className="p-5">
{on ? <Overlay Task={task} SetTask={setTask} /> : <span></span>}
</div>
</div>
);
};
export default Dashboard;
When I console.log(task);
I use the useState with a setter function (as normal) but when updating it (when you click add) I have a delay like shown in the picture but the second time it just works, I am sure there is some problem in my code can anybody help me with it.
I don't always get the right output, it is delayed for example like this:
CodePudding user response:
This is actually how React works, state on React updates Asynchronously, meaning that the state will not update instantly, but instead, it will trigger a rerender and then show the new updated state, this is also mentioned in their docs
There are various techniques you can use for your case, you can check if your priority has a value before rendering the priority data for example:
./components/Overlay.js
import { useState } from "react";
function Overlay({Task, SetTask}) {
const [priority, setPriority] = useState('');
const [text, setText] = useState('');
return (
<div className="bg-[#040e16] p-10 rounded-3xl">
<input type="text" className="bg-[#0d1821] mr-3 w-[30rem] h-10 text-lg rounded-lg p-2" value={text} onChange={e => setText(e.target.value)}/>
<button className="bg-[#0d1821] p-2 w-16 rounded-lg hover:bg-[#3b42a4] transition-all" onClick={() => {SetTask({
text: text,
priority: priority
});
console.log(Task)}}>Add</button><br />
{priority && <>
<p>Priority: {priority}</p> <br />
<button onClick={() => setPriority('high')}><img src="/hi-priority.png" alt="" className="w-12 hover:bg-[#3b42a4] mr-5 transition-all rounded-2xl"/></button>
<button onClick={() => setPriority('medium')}><img src="/md-priority.png" alt="" className="w-12 hover:bg-[#3b42a4] mr-5 transition-all rounded-2xl"/></button>
<button onClick={() => setPriority('low')}><img src="/lo-priority.png" alt="" className="w-12 hover:bg-[#3b42a4] mr-5 transition-all rounded-2xl"/></button>
</> }
</div>
);
}
export default Overlay;
You can also use useEffect to listen to state updates.
useEffect(() => {
console.log(`priority state changed to ${priority}`);
}, [priority]);
CodePudding user response:
Inside the onClick
the SetTask
executes but as we all know state setters are cached for efficiency, the console.log is executed first before setting the Task
object. Once the task
object is set, the component is then re-rendered and you see the correct value the next time.