如何在 2 秒后更新状态?

IT技术 javascript reactjs
2021-05-01 15:59:32

我试图在两秒钟后更新我的视图。但它没有调用更新视图,为什么?

这是我的代码 https://codesandbox.io/s/practical-driscoll-5cvmm

显示初始视图,但两秒钟后它不会更新 DOM。

var fsm = new StateMachine({
    init: "open",
    transitions: [
      { name: "clodsdse", from: "open", to: "closed" },
      { name: "open", from: "closed", to: "open" },
      { name: "openss", from: "closed", to: "open" },
      { name: "ss", from: "a", to: "b" }
    ]
  });

  useEffect(() => {
    d3.select("#graph")
      .graphviz()
      .renderDot(visualize(fsm));
    setTimeout(() => {
      console.log("---");
      update();
    }, 2000);
  }, []);
3个回答

首先,我认为您应该将您的Graph数据保存到您的状态中,然后在您的useEffect钩子中,您可以调用setFsm重新渲染您的Graph。

您也可以部分更新您的图表数据,但在以下示例中,我将仅替换为您的新图表数据。

你也应该叫clearTimeoutuseEffect回传功能,以防止内存泄漏在您的应用程序(以防万一组件之前卸除setFsm的叫法)

我在上一个答案中意识到的一件事是,每次fsm更新时,它都会setTimeout再次调用,从而导致fsm更新,从而导致另一个setTimeout,本质上就像一个无限循环。我已经更新了我的答案,以便setTimeout仅调用onMount,而另一个useEffect仅用于渲染/更新图形。我认为这样的代码更有意义。

您可以使用此代码作为参考。

function App() {
  const [fsm, setFsm] = useState({
    init: "open",
    transitions: [
      { name: "clodsdse", from: "open", to: "closed" },
      { name: "open", from: "closed", to: "open" },
      { name: "openss", from: "closed", to: "open" },
      { name: "ss", from: "a", to: "b" }
    ]
  });

  const renderGraph = () => {
    d3.select("#graph").graphviz().renderDot(visualize(new StateMachine(fsm)));
  };

  // for graph rendering after each update
  useEffect(renderGraph, [fsm]);

  // only setTimeout onMount and clearTimeout willUnmount
  useEffect(() => {
    const timer = setTimeout(() => {
      setFsm({
        init: "open",
        transitions: [
          { name: "clodsdse", from: "open", to: "closed" },
          { name: "open", from: "closed", to: "open" },
          { name: "openss", from: "closed", to: "open" },
          { name: "ss", from: "a", to: "b" },
          { name: "sasdss", from: "a", to: "bb" }
        ]
      });
    }, 2000);
    return () => {
      clearTimeout(timer);
    };
  }, []);

  return (
    <div className="App">
      <div id="graph" />
    </div>
  );
}

不要使用window.d3,使用d3

 const update = () => {
    var fsm = new StateMachine({
      init: "open",
      transitions: [
        { name: "clodsdse", from: "open", to: "closed" },
        { name: "open", from: "closed", to: "open" },
        { name: "openss", from: "closed", to: "open" },
        { name: "ss", from: "a", to: "b" },
        { name: "sasdss", from: "a", to: "bb" }
      ]
    });
    d3 // <-- not window.d3
      .select("#graph")
      .graphviz()
      .renderDot(visualize(fsm));
  };

沙盒

window.d3替换d3它并且它有效。

const update = i => {
    var fsm = new StateMachine({
      init: "open",
      transitions: [
        { name: "clodsde" + i, from: "open", to: "closed" },
        { name: "open", from: "closed", to: "open" },
        { name: "openss", from: "closed", to: "open" },
        { name: "ss", from: "a", to: "b" },
        { name: "sasdss", from: "a", to: "bb" }
      ]
    });
    d3.select("#graph")
      .graphviz()
      .renderDot(visualize(fsm));
  };
  useEffect(() => {
    d3.select("#graph")
      .graphviz()
      .renderDot(visualize(fsm));
    var i = 0;
    setInterval(() => {
      console.log("---");
      update(i);
      i++;
    }, 2000);

我还用 setInterval 替换了 setTimeout 以每 2 秒更新一次。