简体   繁体   中英

Update d3 data react hooks

Got this piece of code:

export default function Chart({ data, changeData}) {
  console.log(data);
  const ref = useRef();

  const createGraph = (data) => {
    var margin = { top: 20, right: 20, bottom: 30, left: 40 },
      width = 1360 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;

    var x = d3.scaleBand().range([0, width]).padding(0.1);
    var y = d3.scaleLinear().range([height, 0]);

    var svg = d3
      .select(ref.current)
      .append("svg")
      .attr("id", "chart")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    x.domain(
      data.map(function (d) {
        return d.name;
      })
    );
    y.domain([
      0,
      d3.max(data, function (d) {
        return d.number;
      }),
    ]);

    // append the rectangles for the bar chart

    const bars = svg.selectAll().data(data).enter().append("rect");

    bars
      .attr("class", "bar")
      .attr("x", function (d) {
        return x(d.name);
      })
      .attr("width", x.bandwidth())
      .attr("y", function (d) {
        return y(d.number);
      })
      .attr("fill", "pink")
      .attr("height", function (d) {
        return height - y(d.number);
      })
      .on("mouseenter", function (actual, i) {
        d3.select(this).attr("opacity", 0.5);
        d3.select(this)
          .transition()
          .duration(300)
          .attr("opacity", 0.6)
          .attr("x", (a) => x(a.name) - 5)
          .attr("width", x.bandwidth() + 10);
      })
      .on("mouseleave", function (actual, i) {
        d3.select(this).attr("opacity", 1);
        d3.select(this)
          .transition()
          .duration(300)
          .attr("opacity", 1)
          .attr("x", (a) => x(a.name))
          .attr("width", x.bandwidth());
      });

    bars
      .append("text")
      .attr("class", "value")
      .attr("x", (a) => x(a.name) + x.bandwidth() / 2)
      .attr("y", (a) => y(a.number) + 30)
      .attr("fill", "blue")
      .attr("text-anchor", "middle")
      .text((a) => `${a.number}%`);

    d3.selectAll("bars").append("text").attr("class", "divergence");
    // add the x Axis
    svg
      .append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

    // add the y Axis
    svg.append("g").call(d3.axisLeft(y));
  };

  useEffect(() => {
    createGraph(data);
  }, [data]);

  return (
    <React.Fragment>
      <Filter>
        <h2>By</h2>
        <span>Popularity</span>
        <span onClick={() => changeData()}>Following</span>
      </Filter>
      <div style={{ marginLeft: "100px" }} ref={ref}></div>
    </React.Fragment>
  );
}

How does one update the data with every render?

I tried creating a function that removes the SVG and adds a new one but the positions are messed up after first render, also I tried using exit() and remove() in useEffect but no results.

The result that I'm trying to achieve is that I have a graph and the data is fetched and passed into this component and whenever I press a button, the data will change. I'm not looking at any animations right now, I just want to see how I can change the data.

It's a bit late but in case anyone happens on this question while searching.

useEffect(() => {
  *// your d3 code here*
  instead of using .enter().append('rect')
  use .join('rect')
}, [data]) *// runs the d3 code every time the data changes*

more about.join() https://observablehq.com/@d3/selection-join

In the return statement specify the svg and g tags.
Instead of ref on the div, do useRef on the svg tag
Instead of.append(g), do.select('.x-axis') etc
This is so that you do not append new g every time the useEffect is run

  <svg ref={d3Container}>
    <g className="chart">
      <g className="x-axis" />
      <g className="y-axis" />
    </g>
  </svg>

I learnt the above after watching the 1st and 3rd video in this series https://muratorium.com/using-react-hooks-with-d3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM