Updating d3 elements in React?

不羁的心 提交于 2021-02-07 08:38:36

问题


I am trying to udpate this bubblechart base on my search input in an input bar. Right now, I put all the d3 code in a Bubble.js, and then in my app.js, I have a searchinput element that will filter my data to be displayed, and then in my Bubble's state, I set its data equal to the filtered data (named RoadmapData). However, my bubble chart is not updating. Actually, each time I type something in, another bubble chart renders, so if I type in 3 letters there are three same and unfiltered bubble charts.

Here is my code right now:

import React, { Component } from "react";
import * as d3 from "d3";

class Bubble extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dataset: { children: this.props.RoadmapData }
    };
  }

  componentWillReceiveProps(nextProps) {
    var diameter = 600;
var color = d3.scaleOrdinal(d3.schemeCategory10);

var bubble = d3
  .pack(this.state.dataset)
  .size([diameter, diameter])
  .padding(1.5);

var svg = d3
  .select("body")
  .append("svg")
  .attr("width", diameter)
  .attr("height", diameter)
  .attr("class", "bubble");

var nodes = d3.hierarchy(this.state.dataset).sum(function(d) {
  return d.Count;
});

var node = svg
  .selectAll(".node")
  .data(bubble(nodes).descendants())
  .enter()
  .filter(function(d) {
    return !d.children;
  })
  .append("g")
  .attr("class", "node")
  .attr("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  });
node.append("title").text(function(d) {
  return d.Name + ": " + d.Count;
});

node
  .append("circle")
  .attr("r", function(d) {
    return d.r;
  })
  .style("fill", function(d, i) {
    return color(i);
  });

node
  .append("text")
  .attr("dy", ".2em")
  .style("text-anchor", "middle")
  .text(function(d) {
    return d.data.Name.substring(0, d.r / 3);
  })
  .attr("font-family", "sans-serif")
  .attr("font-size", function(d) {
    return d.r / 5;
  })
  .attr("fill", "white");

node
  .append("text")
  .attr("dy", "1.3em")
  .style("text-anchor", "middle")
  .text(function(d) {
    return d.data.Count;
  })
  .attr("font-family", "Gill Sans", "Gill Sans MT")
  .attr("font-size", function(d) {
    return d.r / 5;
  })
  .attr("fill", "white");
  }

  render() {
return <div>{this.node}</div>;
  }
}

export default Bubble;

I am a beginner in d3, but I feel like the problem is either that I am using lifecycle methods wrong ( I used componentWillReceiveProps here, when I used componentMount() and typed in my search bar, nothing changed. Or maybe I shouldn't return this.node? Thanks in advance.


回答1:


What's happening is that each time your component is re-rendered, the componentWillReceiveProps function is creating a new instance of the visualization and adding it to the <div> node created by React, via the calls to node.append. You can avoid this by removing the previously created instances via the d3 remove() function.

If you're willing to introduce another library, there's one called React Faux Dom that would allow you to avoid all the React lifecycle stuff and just do everything in the render() function as normal. It may simplify things a little.

You also mention that the chart is unfiltered every time - this is because you only assign the data prop to state in the constructor - this only runs once when your component is first created. In this case, it looks like you can safely remove this and read the data from this.props.RoadmapData every time (It doesn't appear that you are making any changes to the state inside the component).

You'd just need to add a line at the beginning of render() to get the data into the right format for d3, something like:

var roadmapDataForD3 = { children: this.props.RoadmapData };



来源:https://stackoverflow.com/questions/54120318/updating-d3-elements-in-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!