reactjs React子组件不会注意到useEffect内部异步函数的状态更改

qlvxas9a  于 2023-02-18  发布在  React
关注(0)|答案(1)|浏览(143)

我试图传递一个在async函数内部生成的状态,而这个函数本身又在useState内部,我了解到useRef可能是实现这个目的的最佳方法,因为它可以引用可变状态,在这个过程中我了解了react-useStateRef,这最终解决了我在主组件内部从未更新状态的另一个问题(会不断地得到“太多呈现”的错误)。所以它本质上充当了useRef和useState的一个角色。
但是,虽然我的状态最终更新了,但它仍然没有传递到我的Canvas组件。我试图根据从数据集获得的温度更新画布的BG图形。

import { useEffect } from 'react';
import useState from 'react-usestateref';
import { getServerData } from './serviceData';
import "./App.css"
import Canvas from './components/Canvas';

function App() {
  const [dataset, setDataset] = useState(null);
  const [units, setUnits] = useState('metric');

  // canvas background graphic stuff
  var [currentBG, setCurrentBG, currentBGref] = useState(null);

  useEffect(() => {
    const fetchServerData = async () => {
      const data = await getServerData(city, units);
      setDataset(data);

      function updateBG() {
        const threshold = units === "metric" ? 20 : 60;
        if (data.temp <= threshold) {
        setCurrentBG('snow');
        }
        else {
        setCurrentBG('sunny');
        }
      }
      updateBG();
    }
    fetchServerData();
    console.log(currentBG)
  }, [city, units, currentBGref.current, currentFGref.current])
    const isCelsius = currentUnit === "C";
    button.innerText = isCelsius ? "°F" : "°C";
    setUnits(isCelsius ? "metric" : "imperial");
  };

  return (
    <div className="app">
        { dataset && ( <Canvas width={640} height={480} currentBG={currentBGref.current}></Canvas> )}
    </div>
  );
}

export default App;

我只能传递初始值,它永远不会更新超过这个值,尽管useEffect内部的console.log显示它确实在更新,那么为什么它不传递给我的组件呢?

bjg7j2ky

bjg7j2ky1#

useStateRef看起来是一个反模式。您可以决定新状态是什么,以便在极有可能需要另一个引用时,您总是可以自己创建一个。我建议最小化画布上的属性,以防止不必要的重新呈现。

function App({ width, height }) {
  const canvas = React.useRef()
  const [color, setColor] = React.useState("white")

  // when color changes..
  React.useEffect(() => {
    if (canvas.current) {
      const context = canvas.current.getContext('2d');
      context.fillStyle = color
      context.fillRect(0, 0, width, height)
    }
  }, [color, width, height])

  return <div>
    <canvas ref={canvas} width={width} height={height} />
    <button onClick={_ => setColor("blue")} children="blue" />
    <button onClick={_ => setColor("green")} children="green" />
    <button onClick={_ => setColor("red")} children="red" />
  </div>
}

ReactDOM.createRoot(document.querySelector("#app")).render(<App width={200} height={150} />)
canvas { display: block; border: 1px solid black; }
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

或者,也许没有理由将颜色存储为状态,您可以创建自己的setColor函数,并将其作为事件侦听器附加-
一个一个三个一个一个一个一个一个四个一个一个一个一个一个五个一个
我还建议您看看SVG。我发现带有React模式的API比Canvas API好得多。它们的功能各不相同,但如果SVG能满足您的需要,那么值得考虑。

相关问题