I want to attach a payload of an mqtt message to an existing array in a state in REACT.
The problem is, that the state is not updated correctly. It is updated in the same component but when the next message arrives the state is again an empty array (as in the useState declaration).
The expected behavior should be, that the size is increasing by one by every incoming mqtt message.
const [stateMeasurements, setStateMeasurements] = useState([]);
useEffect(()=>{
mqttClient.on('message', function (topic, message) {
var payload = { topic, message: JSON.parse(message) }
setStateMeasurements([...stateMeasurements, payload.message]);
}
)
}, []);
Because this effect is only rendered ones, I tried to move the setStateMeasurements call to an function outside the useEffect, too.
const [stateMeasurements, setStateMeasurements] = useState([]);
function funcSetStateMeasurements (message) {
setStateMeasurements([...stateMeasurements, message]);
}
useEffect(()=>{
mqttClient.on('message', function (topic, message) {
var payload = { topic, message: JSON.parse(message) }
funcSetStateMeasurements(payload.message);
}
)
}, []);
Unfortunately it shows the same behavior…
I think it is again one of the basic problems of understanding the render behavior of REACT.
Thanks in advance!
2
Answers
Since the
stateMeasurements
is not the dependency ofuseEffect
hook, the value ofstateMeasurements
insideuseEffect
hook will always be the initial value[]
. To use the previous value of it, try Updating state based on the previous stateYou may pass an updater function to the
setStateMeasurements
setter function.An example: codesandbox
The standard way of solving this issue would be to include
stateMeasurements
in the dependency array.To prevent a stacking amount of event handlers we also need to supply
useEffect
with a way to detach these events. To do this we return a function touseEffect
that the hook uses for cleanup.This will attach an message handler that uses the value
stateMeasurements
. However each timestateMeasurements
is updated, React will detach the old handler and assign a new handler with the updatedstateMeasurements
value.Since you are only trying to update
stateMeasurements
based on its previous value, using an updater function like described in the answer of Lin Du might be better suited. An updater function always receives the current value in its arguments. And sincesetStateMeasurements
has a stable identity you don’t need to include it in the dependency array.Note that you probably still want to detach the event when the component unmounts, so adding
return () => mqttClient.off(...)
is still a good idea.