I have been battling with this for a while and I would really appreciate any pointers you could give me.
I am building a simple electron app using react for a custom macro keypad I made using a programmable microcontroller. Communication is handled via serial port and works as intended. I would like to be able to select one of the buttons by either clicking on the GUI (working) or by pressing the actual key directly on the keypad (not working).
To be more specific, the setter gets properly called on click but not on serial port read.
import './App.css';
import Key from './components/Key';
import styled from "styled-components";
import React, { useEffect, useState } from 'react';
const KeyHolder = styled.div`
display: grid;
grid-template-columns: repeat(4, 100px);
gap: 1rem;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
`;
const App = () => {
const [isPortOpen, setPortOpen] = useState(false);
const [selectedKey, setSelectedKey] = useState('');
useEffect(() => console.log('selectedKey', selectedKey), [selectedKey]);
useEffect(() => console.log(isPortOpen), [isPortOpen]);
const connect = async () => {
try {
const ports = await navigator.serial.getPorts();
const port = ports[0];
await port.open({ baudRate: 9600 });
setPortOpen(true);
// eslint-disable-next-line no-undef
const decoder = new TextDecoderStream();
port.readable.pipeTo(decoder.writable);
const inputStream = decoder.readable;
const reader = inputStream.getReader();
while (true) {
const { value, done } = await reader.read();
if (value) {
console.log("key pressed: ",value); // This correctly logs the pressed key
setSelectedKey(value); // This setter does not trigger the useEffect()
}
if (done) {
console.log('DONE');
}
}
} catch (error) {
console.warn(error);
}
}
if (!isPortOpen) {
connect();
}
return (
<div className="App">
<header className="App-header">
<KeyHolder>
{/* All this setters work as intended and trigger the useEffect() */}
<Key isPressed={selectedKey === '5'} onClick={() => setSelectedKey('5')} />
<Key isPressed={selectedKey === '6'} onClick={() => setSelectedKey('6')} />
<Key isPressed={selectedKey === '7'} onClick={() => setSelectedKey('7')} />
<Key isPressed={selectedKey === '8'} onClick={() => setSelectedKey('8')} />
<Key isPressed={selectedKey === '1'} onClick={() => setSelectedKey('1')} />
<Key isPressed={selectedKey === '2'} onClick={() => setSelectedKey('2')} />
<Key isPressed={selectedKey === '3'} onClick={() => setSelectedKey('3')} />
<Key isPressed={selectedKey === '4'} onClick={() => setSelectedKey('4')} />
</KeyHolder>
</header>
</div>
);
}
export default App;
Could the problem be that the setter is being called from within an async function? If that is the case, coud you point me to some resources on how to avoid that issue?
Thank you very much in advance.
You can place your connect() inside useEffect
like so
useEffect(() => {
if (!isPortOpen) {
connect();
}
}, [isPortOpen])