'useState updates one time only
I have some issues on my useState hook. Everytime the tag "AWESOME" is read, it should toggle the state.
That way I can make a timer for that tag. It works for the first time (so the timer starts when "AWESOME" is read) but my state won't update to true. Every time I read the tag, after the first time, the state keeps logging false. Any advice?
I know about the dependencies of the useEffect hook, first I used }, []); at the end, that still keeps the tag reader active, so I was able to read RFID tags after useEffect was done. Now I've tried it with }, [running]; which results the same.
I also tried a infinite-loop, but that crashed my app (error: insufficient resources), and also didn't work.
/* eslint-disable no-undef */
import React, { useState, useEffect } from "react";
function Stopwatch() {
const [time, setTime] = useState(0);
const [running, setRunning] = useState(false);
const [debug, setDebug] = useState(false);
useEffect(() => {
let interval;
if (running) {
interval = setInterval(() => {
setTime((prevTime) => prevTime + 10);
}, 10);
} else if (!running) {
clearInterval(interval);
}
return () => clearInterval(interval);
}, [running]);
useEffect(() => {
var conn = new phidget22.Connection();
conn.connect().then(function() {
var ch = new phidget22.RFID();
// Register for event before calling open ch.onTag = function(tag, protocol) {
ch.onTag = function(tag, protocol) {
console.log("Tag detected: " + tag);
{debug && console.log("Tag protocol: " + protocol);}
if(tag === "AWESOME") {
action();
}
};
ch.open().catch(function(err) {
console.error("Error during open:", err);
});
}).catch(function (err) {
console.error("Error during connect:", err);
});
}, []);
function action() {
if(running) {
setRunning(false);
} else {
setRunning(true)
}
}
return (
<div className="stopwatch">
<div className="numbers">
<span>{("0" + Math.floor((time / 60000) % 60)).slice(-2)}:</span>
<span>{("0" + Math.floor((time / 1000) % 60)).slice(-2)}:</span>
<span>{("0" + ((time / 10) % 100)).slice(-2)}</span>
</div>
<div className="buttons">
<button onClick={() => setTime(0)}>Reset</button>
</div>
</div>
);
};
export default Stopwatch;
Solution 1:[1]
First problem is your second useEffect hook. it depends on the 'running' value changing, while you are changing the 'running' value inside of the useEffect hook that depends 'running' (chicken and egg type of scenario). This will cause issues and setting the 'running' state needs to be removed from the useEffect that depends on it changing.
Second, the approach you are taking you can think of as a light switch. If you change the running tag from false to true then vis versa every time a value (such as AWSOME) equals true, this will be the same as turning a light switch on and off in rapid succession in your home.
TL;DR To get past your current hurdle, you want to set your running state value outside of your useEffects, and change it on a specific event.
remove:
if(tag === "AWESOME") {
setRunning(!running)
console.log(running)
}
};
And then Add:
<div className="buttons">
<button onClick={() => setRunning((prevBool) => !prevBool)}>Change Running Value</button>
</div>
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 | Colegit |
