简体   繁体   English

在函数内部反应设置状态

[英]React Setting state inside of a function

I am using some d3 for visualization and decided to also use reactstrap. 我正在使用一些d3进行可视化,并决定也使用reactstrap。 Basically clicking a circle in d3 will result in the reactstrap element Collapse to appear. 基本上,单击d3中的一个圆圈将导致reactstrap元素“折叠”出现。

I am not finding any luck with setState... I am doing all my react code in componenetDidMount(), inside of componentDidMount(), I have a function update(), and in update, I have a function called click, and when click triggers, it does: 我在setState中找不到任何运气...我正在componenetDidMount()中,componentDidMount()内执行所有反应代码,有一个update()函数,在更新中有一个名为click的函数,当点击触发器,它可以:

this .setState({ collapse: !this.state.collapse }); 这个 .setState({崩溃:!this.state.collapse});

It doesn't work, and I lack the fundamental JS to reason why, I am assuming that the this keyword is referring to the function update instead of my component "Tree"? 它不起作用,并且我缺少基本的JS来解释为什么,我假设this关键字是指函数update而不是组件“ Tree”?

Code: 码:

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;

Sorry if that's a lot of code, I deleted my var treeData which is a json object 100 lines long 抱歉,如果有很多代码,我删除了var treeData,它是一个100行长的json对象

You won't get this context inside the regular function unless you bind this to the function or change it to arrow function 除非将其绑定到函数或将其更改为箭头函数,否则不会在常规函数中获得此上下文

So, Change 所以,改变

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

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

To

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

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

Or bind it manually 或手动绑定

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

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

Or move the function outside componentDidMount and do manual binding in constructor as 或将函数移到componentDidMount外部,并在构造函数中手动绑定为

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

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

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