代码之家  ›  专栏  ›  技术社区  ›  Acy

函数内部的反应设置状态

  •  2
  • Acy  · 技术社区  · 7 年前

    我使用一些d3进行可视化,并决定也使用reactstrap。基本上,在d3中单击一个圆将导致reactstrap元素塌陷。

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

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

    代码:

    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;
    

    1 回复  |  直到 7 年前
        1
  •  4
  •   Hemadri Dasari    7 年前

    除非将其绑定到函数或将其更改为箭头函数,否则无法在常规函数中获取此上下文

    所以,改变

      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);
      }
    

    或者手工绑定

       function click2(d) {
        this.setState({ collapse: !this.state.collapse });
    
        alert("You clicked on more!" + d.data.name);
      }.bind(this)
    

    或者将函数移到componentDidMount之外,并在构造函数中手动绑定为

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