Home > Software engineering >  Why when setting the state in React doesn't give the right value all the time?
Why when setting the state in React doesn't give the right value all the time?

Time:12-19

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: when clicking the add button

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.

  • Related