useState() setter 不在异步函数内部触发(电子)

useState() setter not triggering inside an async function (electron)

我已经为此苦苦挣扎了一段时间,非常感谢您能给我的任何指示。

我正在为我使用可编程微控制器制作的自定义宏键盘使用 React 构建一个简单的电子应用程序。通信通过串行端口处理并按预期工作。我希望能够通过单击 GUI(有效)或直接按键盘上的实际键(无效)来 select 其中一个按钮。

更具体地说,setter 在点击时被正确调用,但在串口读取时没有被正确调用。

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;

问题可能是 setter 是从异步函数中调用的吗?如果是这样的话,你能给我一些关于如何避免这个问题的资源吗?

非常感谢您。

您可以像这样将 connect() 放在 useEffect

useEffect(() => {
  if (!isPortOpen) {
    connect();
  }
}, [isPortOpen])

这没有回答您的问题,但也许您会发现此 post 很有帮助。

我以前没见过 styled-components,觉得很有趣我可以在 JavaScript 的 单行 行中替换 33,500 Bytes package with 10 dependencies , styled 下面.

function styled(Tag, style = {}) {
  return props => <Tag style={style} {...props} />
}

const Foo = styled("div", {backgroundColor: "blue", padding: "1rem" })
const Big = styled("button", {fontSize: "3rem"})

function App() {
  return <Foo>
    <Big onClick={e => console.log("hello")}>
      Hello
    </Big>
  </Foo>
}

ReactDOM.render(<App/>, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.development.js"></script>
<div id="app"></div>