javascript - React 在函数内部设置状态

标签 javascript reactjs d3.js

我正在使用一些 d3 进行可视化,并决定也使用 Reactstrap。基本上,单击 d3 中的圆圈将导致 Reactstrap 元素 Collapse 出现。

我在 setState 方面没有找到任何运气...我正在 componenetDidMount() 中执行所有的 react 代码,在 componentDidMount() 内部,我有一个函数 update(),并且在 update 中,我有一个名为 click 的函数,当点击触发时,它会:

this.setState({ crash: !this.state.collapse });

它不起作用,而且我缺乏基本的 JS 来解释为什么,我假设 this 关键字指的是函数更新而不是我的组件“Tree”?

代码:

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

import { Collapse, Button, CardBody, Card } from "reactstrap";

class Tree extends Component {
  constructor(props) {
    super(props);
    this.state = { collapse: false };
    this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
    //this.toggle = this.toggle.bind(this);
  }

  componentDidMount() {
    this.updateWindowDimensions();


    // Set the dimensions and margins of the diagram
    var height1 = window.innerHeight;
    var margin = { top: 10, right: 90, bottom: 30, left: 180 },
      width = 1080 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;

    // append the svg object to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3
      .select("body")
      .append("svg")
      .attr("width", window.innerWidth - margin.right - margin.left)
      .attr("height", window.innerHeight - margin.top - margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var i = 0,
      duration = 500,
      root;

    // declares a tree layout and assigns the size
    var treemap = d3.tree().size([window.innerHeight, window.innerWidth]);

    root = d3.hierarchy(treeData, function(d) {
      return d.children;
    });
    root.x0 = height / 2;
    root.y0 = 0;

    // Collapse after the second level
    root.children.forEach(collapse);

    update(root);

    // Collapse the node and all it's children
    function collapse(d) {
      if (d.children) {
        d._children = d.children;
        d._children.forEach(collapse);
        d.children = null;
      }
    }

    function update(source) {
      // Assigns the x and y position for the nodes

      var treeData = treemap(root);

      // Compute the new tree layout.
      var nodes = treeData.descendants(),
        links = treeData.descendants().slice(1),
        more_button = treeData.descendants();

      // Normalize for fixed-depth.
      nodes.forEach(function(d) {
        d.y = d.depth * 360;
      });

      // ****************** Nodes section ***************************

      // Update the nodes...
      var node = svg.selectAll("g.node").data(nodes, function(d) {
        return d.id || (d.id = ++i);
      });

      // Enter any new modes at the parent's previous position.
      var nodeEnter = node
        .enter()
        .append("g")
        .attr("class", "node")

        //if deleted, bubbles come from the very top, is weird
        .attr("transform", function(d) {
          return "translate(" + source.y0 + "," + source.x0 + ")";
        });

      // Add Circle for the nodes
      nodeEnter
        .append("circle")
        .attr("class", "node")
        .attr("r", 1e-6)
        .style("fill", function(d) {
          return d._children ? "lightsteelblue" : "#fff";
        });

      /*
// Add labels for the nodes
      nodeEnter
        .append("text")
        .attr("dy", 0)
        .attr("x", function(d) {
          return d.children || d._children ? -13 : 13;
        })
        .attr("text-anchor", function(d) {
          return d.children || d._children ? "end" : "start";
        })
        .text(function(d) {
          return d.data.name;
        });
*/
      var diameter = 50;
      nodeEnter
        .append("image")
        .on("click", click)
        .attr("xlink:href", function(d) {
          return d.data.img;
        })
        .attr("height", diameter * 2)
        .attr("transform", "translate(-50," + -50 + ")");

      // UPDATE
      var nodeUpdate = nodeEnter.merge(node);

      // Transition to the proper position for the node
      nodeUpdate
        .transition()
        .duration(duration)
        .attr("transform", function(d) {
          return "translate(" + d.y + "," + d.x + ")";
        });

      // Update the node attributes and style
      nodeUpdate
        .select("circle.node")
        .attr("r", diameter)

        .style("fill", function(d) {
          return d._children ? "lightsteelblue" : "#fff";
        })
        .attr("cursor", "pointer");

      nodeUpdate
        .append("circle")
        .on("click", click2)
        .attr("additional", "extra_circle")
        .attr("r", 20)
        .attr("transform", "translate(0," + -65 + ")");
      // Remove any exiting nodes
      var nodeExit = node
        .exit()
        .transition()
        .duration(duration)
        .attr("transform", function(d) {
          return "translate(" + source.y + "," + source.x + ")";
        })
        .remove();

      // On exit reduce the node circles size to 0
      nodeExit.select("circle").attr("r", 1e-6);

      // On exit reduce the opacity of text labels
      nodeExit.select("text").style("fill-opacity", 1e-6);

      // ****************** links section ***************************

      // Update the links...
      var link = svg.selectAll("path.link").data(links, function(d) {
        return d.id;
      });

      // Enter any new links at the parent's previous position.
      var linkEnter = link
        .enter()
        .insert("path", "g")
        .attr("class", "link")
        .attr("d", function(d) {
          var o = { x: source.x0, y: source.y0 };
          return diagonal(o, o);
        });

      // UPDATE
      var linkUpdate = linkEnter.merge(link);

      // Transition back to the parent element position
      linkUpdate
        .transition()
        .duration(duration)
        .attr("d", function(d) {
          return diagonal(d, d.parent);
        });

      // Remove any exiting links
      var linkExit = link
        .exit()
        .transition()
        .duration(duration)
        .attr("d", function(d) {
          var o = { x: source.x, y: source.y };
          return diagonal(o, o);
        })
        .remove();

      // Store the old positions for transition.
      nodes.forEach(function(d) {
        d.x0 = d.x;
        d.y0 = d.y;
      });

      // Creates a curved (diagonal) path from parent to the child nodes
      function diagonal(s, d) {
        var path = `M ${s.y} ${s.x}
            C ${(s.y + d.y) / 2} ${s.x},
              ${(s.y + d.y) / 2} ${d.x},
              ${d.y} ${d.x}`;

        return path;
      }

      // Toggle children on click.
      function click(d) {
        if (d.children) {
          d._children = d.children;
          d.children = null;
        } else {
          d.children = d._children;
          d._children = null;
        }
        update(d);
      }
      function click2(d) {
        this.setState({ collapse: !this.state.collapse });

        alert("You clicked on more!" + d.data.name);
      }
    }
  }

  updateWindowDimensions() {
    this.setState({ width: window.innerWidth, height: window.innerHeight });
  }



  render() {
    return (
      <div>
        <Button
          color="primary"

          style={{ marginBottom: "1rem" }}
        >
          Toggle
        </Button>
        <Collapse isOpen={this.state.collapse}>
          <Card>
            <CardBody>
              Anim pariatur cliche reprehenderit, enim eiusmod high life
              accusamus terry richardson ad squid. Nihil anim keffiyeh
              helvetica, craft beer labore wes anderson cred nesciunt sapiente
              ea proident.
            </CardBody>
          </Card>
        </Collapse>
      </div>
    );
      }
    }

    export default Tree;

抱歉,如果代码太多,我删除了我的 var treeData,它是一个 100 行长的 json 对象

最佳答案

除非将 this 绑定(bind)到函数或将其更改为箭头函数,否则您不会在常规函数内获得此上下文

所以,改变

  function click2(d) {
    this.setState({ collapse: !this.state.collapse });

    alert("You clicked on more!" + d.data.name);
  }

  const click2 = d => {
    this.setState({ collapse: !this.state.collapse });

    alert("You clicked on more!" + d.data.name);
  }

或者手动绑定(bind)

   function click2(d) {
    this.setState({ collapse: !this.state.collapse });

    alert("You clicked on more!" + d.data.name);
  }.bind(this)

或者将函数移到 componentDidMount 外部并在构造函数中手动绑定(bind)

    this.click2 = this.click2.bind(this);

关于javascript - React 在函数内部设置状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54337541/

相关文章:

javascript - 将计数器旋转到包含两位数字的数字

php - 赋予网页地址属性

javascript - 为什么第二个循环在第一个循环之前执行?

javascript - 消除不同mapStateToProps之间的冗余

javascript - 在 react 中从不同的文件夹加载CSS

svg - 如何使用D3/人力车在时间序列图上标记离散点?

d3.js - D3.js scaleOrdinal不支持rangeRoundBands方法

javascript - 选择使用 css 类所需的选项输入

javascript - React 组件中的 ES2015 非变异数组交换(或通量操作)

javascript - 当我在 D3 中触发的事件中删除相应的元素时,如何删除元素的事件监听器?