简体   繁体   English

无法将 d3 与反应一起使用

[英]Unable to use d3 with react

I wanted to display a d3 graphics inside a modal window created using react-bootstrap.我想在使用 react-bootstrap 创建的模态 window 中显示 d3 图形。 First I tried displaying d3 circle directly inside (non-modal) div element.首先,我尝试直接在(非模态) div元素内显示 d3 圆圈。 I tried it as follows:我尝试如下:

import "./styles.css";
import React from "react";
import * as d3 from "d3";

export default class App extends React.Component {
  testRef = React.createRef();

  constructor(props) {
    super(props);
    this.changeText = this.changeText.bind(this);
  }

  async changeText() {

    let svg = d3
      .select(this.testRef.current)
      .append("svg")
      .attr("width", 200)
      .attr("height", 200);

    // Add the path using this helper function
    svg
      .append("circle")
      .attr("cx", 100)
      .attr("cy", 100)
      .attr("r", 50)
      .attr("stroke", "black")
      .attr("fill", "#69a3b2");
    // this.testRef.current.innerHtml = "Test123";
  }

  render() {
    return (
      <>
        <div className="App">
          <div ref={this.testRef} />
          <button onClick={this.changeText}> Draw circle inside div </button>
        </div>
      </>
    );
  }
}

And its working as can be seen in this codesandbox :它的工作可以在这个代码框中看到:

在此处输入图像描述

Now I tried to add d3 circle to modal popup created using react-bootstrap as shown below:现在我尝试将 d3 circle 添加到使用 react-bootstrap 创建的模式弹出窗口中,如下所示:

import React from "react";
import ReactDOM from "react-dom";
import Modal from "react-bootstrap/Modal";
import Button from "react-bootstrap/Button";
import ButtonToolbar from "react-bootstrap/ButtonToolbar";
import * as d3 from "d3";

import "./styles.css";

class App extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = { modalShow: false };
  }

  testRef = React.createRef();

  showD3 = () => {
    this.setState({ modalShow: true });
    // console.log(this.testRef.current);
    let svg = d3
      .select(this.testRef.current)
      .append("svg")
      .attr("width", 200)
      .attr("height", 200);

    // Add the path using this helper function
    svg
      .append("circle")
      .attr("cx", 100)
      .attr("cy", 100)
      .attr("r", 50)
      .attr("stroke", "black")
      .attr("fill", "#69a3b2");
  };

  render() {
    let modalClose = () => this.setState({ modalShow: false });

    return (
      <>
        <ButtonToolbar>
          <Button variant="primary" onClick={this.showD3}>
            Launch vertically centered modal
          </Button>
        </ButtonToolbar>
        <Modal show={this.state.modalShow} onHide={modalClose}>
          <Modal.Header closeButton>
            <Modal.Title>Modal heading</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            D3 in React
            <div ref={this.testRef}></div>
          </Modal.Body>
        </Modal>
      </>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

However this doesnt work as can be seen in this codesandbox :但是,这不起作用,可以在此代码框中看到:

在此处输入图像描述

It does show the modal dialog, but without D3 circle.它确实显示了模态对话框,但没有 D3 圆圈。 Why is this so?为什么会这样?

Referenecs: 1 , 2参考文献: 1 , 2

I realized that we have to handle rendering in component life cycle methods.我意识到我们必须在组件生命周期方法中处理渲染。 In this case in componentDidMount method.在这种情况下,在componentDidMount方法中。 We have to just manipulate the state in the click event.我们只需要在点击事件中操作 state。 I was able to do this with class components as follows:我能够使用 class 组件执行此操作,如下所示:

import React from "react";
import ReactDOM from "react-dom";
import Modal from "react-bootstrap/Modal";
import Button from "react-bootstrap/Button";
import ButtonToolbar from "react-bootstrap/ButtonToolbar";
import * as d3 from "d3";

import "./styles.css";

class App extends React.Component {
  constructor(...args) {
    super(...args);
    let _color = "#" + Math.floor(Math.random() * 16777215).toString(16);
    this.state = { modalShow: false, color: _color, showChart: false };
  }

  chart = React.createRef();

  componentDidUpdate() {
    if (this.state.modalShow) {
      this.renderChart();
    }
  }

  renderChart() {
    let svg = d3
      .select(this.chart.current)
      .append("svg")
      .attr("width", 200)
      .attr("height", 200);

    svg
      .append("circle")
      .attr("cx", 100)
      .attr("cy", 100)
      .attr("r", 50)
      .attr("stroke", "black")
      .attr("fill", this.state.color);
  }

  changeChartState() {
    let _color = "#" + Math.floor(Math.random() * 16777215).toString(16);
    this.setState({ color: _color });
  }

  showD3 = () => {
    this.setState({ modalShow: true });
    this.changeChartState();
  };

  render() {
    let modalClose = () => this.setState({ modalShow: false });

    return (
      <>
        <ButtonToolbar>
          <Button variant="primary" onClick={this.showD3}>
            Launch vertically centered modal
          </Button>
        </ButtonToolbar>
        <Modal show={this.state.modalShow} onHide={modalClose}>
          <Modal.Header closeButton>
            <Modal.Title>Modal heading</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            D3 in React
            <div ref={this.chart}></div>
          </Modal.Body>
        </Modal>
      </>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Here is the working codesandbox . 这是工作代码框

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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