reactjs D3元素点击不更新React状态

j8ag8udp  于 2023-03-29  发布在  React
关注(0)|答案(2)|浏览(146)

我使用D3和react useEffect钩子,我用useCallback钩子 Package 了click方法并更新了状态,但是当我点击元素时,元素状态根本没有更新。为了停止重新渲染D3 SVG元素,我不想将counter作为依赖项添加到useEffect钩子。
我可以更新counter状态而不添加counteruseEffect的依赖关系吗?
CodeSandbbox

import { useEffect, useState, useCallback } from "react";
import * as d3 from "d3";

export default function App() {
  const [counter, setCounter] = useState(0);

  const handleClick = useCallback(() => {
    setCounter(counter + 1);
      console.log(counter);
  }, [counter]); 

  useEffect(() => {
    const svg = d3.select("#svg");

    //naming the selection
    const redRect = svg
      .append("rect")
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", 300)
      .attr("height", 300)
      .attr("fill", "red")
      .attr("id", "red-rect");

    redRect.on("click", handleClick);
  }, []); // should not re-render the d3 with counter as the dependency 

  return <svg id="svg" />;
}
x8diyxa7

x8diyxa71#

我已经找到了阻止useEffect的方法,用useRef重做所有D3的东西,我使用useRef值作为D3 SVG rect,然后我检查rectRef.current是否存在,然后忽略D3方法并将handleClick绑定到rectRef.current

import { useEffect, useState, useCallback, useRef } from "react";
import * as d3 from "d3";

let calls = 0;

console.log();

export default function App() {
  const [counter, setCounter] = useState(0);

  const rectRef = useRef(null);

  const handleClick = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  useEffect(() => {
    if (rectRef.current === null) {
      const svg = d3.select("#svg");
      calls += 1;
      console.log("Re-rendered: " + calls); // calls only one time
      //naming the selection
      rectRef.current = svg.append("rect");
      rectRef.current
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", 300)
        .attr("height", 300)
        .attr("fill", "red")
        .attr("id", "red-rect");
    } else {
      rectRef.current.on("click", handleClick);
    }
  }, [handleClick]);

  return (
    <div>
      <svg id="svg" />

      <div>{counter}</div>
    </div>
  );
}

CodeSandbox

mccptt67

mccptt672#

setCounter传递一个函数。该函数的参数是状态的前一个值。

const handleClick = useCallback(() => {
    setCounter((prev) => prev + 1);
  }, []);

useCallback在这里是不必要的,因为setCounter不会改变标识。useReducer也是一个更好的钩子,只用于增量。

const [counter, incrementCounter] = useReducer((x) => x+1, 0);

  useEffect(() => {
    console.log("render"); // Renders once (or twice in strict mode)
    const svg = d3.select("#svg");

    //naming the selection
    const redRect = svg
      .append("rect")
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", 300)
      .attr("height", 300)
      .attr("fill", "red")
      .attr("id", "red-rect");

    redRect.on("click", incrementCounter);
  }, [incrementCounter]); // dependency is not necessary, but doesn't hurt.

Code Sandbox
片段
一个一个二个一个一个一个三个一个一个一个一个一个四个一个

相关问题