简体   繁体   中英

d3 elements not showing in react

I am using react with d3js, but for some reason the d3 container div is not rendering. I suspect that something is not done correctly when selecting the local div, but I can't figure out what.

The index.html & the index.js files are just plain boilerplate code and the only modification is in the App.jsx file posted below

import React from "react";
import * as d3 from "d3";

function App() {
  const data = [
    { name: "A", score: 70 },
    { name: "B", score: 90 },
    { name: "C", score: 50 }
  ];

  const width = 800;
  const height = 800;
  const margin = { top: 50, bottom: 50, left: 50, right: 50 };

  const svg = d3
    .select("#container")
    .append("svg")
    .attr("width", width - margin.left - margin.right)
    .attr("height", height - margin.top - margin.bottom)
    .attr("viewbox", [0, 0, width, height]);

  const x = d3
    .scaleBand()
    .domain(d3.range(data.length))
    .range([margin.left, width - margin.right])
    .padding(0.1);

  const y = d3
    .scaleLinear()
    .domain([0, 100])
    .range([height - margin.bottom, margin.top]);

  svg
    .append("g")
    .attr("fill", "royalblue")
    .selectAll("rect")
    .data(data.sort((a, b) => d3.descending(a.score, b.score)))
    .join("rect")
    .attr("x", (d, i) => x(i))
    .attr("y", (d) => y(d.score))
    .attr("width", x.bandwidth())
    .attr("height", (d) => y(0) - y(d.score));

  svg.node();

  return (
    <div>
      <h1>Chart</h1>
      <div id="container"></div>
    </div>
  );
}
export default App;

Think about the state of the world as your code runs:

  • The App component is rendered on page load.
  • We call d3.select('#container') , but nothing happens. There's no div with that ID on the page because we haven't gotten that far yet.
  • The D3 operations continue, likely throwing no errors because by design, D3 allows you to operate on empty selections.
  • We return a JSX value describing the DOM we want React to render. Sometime shortly after we return this, the elements are rendered into the page.
  • Now we have the #container element but our selection code does not re-run, because nothing triggers the component to re-render.

You might consider using a callback ref - here's a minimal example:

const doD3Stuff = (element) => {
  const width = 800;
  const height = 800;
  const margin = { top: 50, bottom: 50, left: 50, right: 50 };

  const svg = d3
    // the select method can accept an actual element instead of a selector
    .select(element)
    .append("svg");

  // etc.
};

const App = () => {
  return (
    <div>
      <h1>Chart</h1>
      <div id="container" ref={doD3Stuff} />
    </div>
  );
};

This is a starting point, but of course it doesn't get into what happens when data changes and you want to things to redraw, animate, etc.

React and D3 can work well together . But even when using just one of them by itself, it's good to understand the execution model - when code runs, and when it doesn't. When using them together, it's way more important to have this level of understanding, or things will happen that you'll have difficulty troubleshooting.

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