在函数内部反应设置状态 [英] React Setting state inside of a function

查看:46
本文介绍了在函数内部反应设置状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用d3进行可视化,并决定也使用reactstrap.基本上,单击d3中的一个圆圈将导致reactstrap元素折叠"出现.

I am using some d3 for visualization and decided to also use reactstrap. Basically clicking a circle in d3 will result in the reactstrap element Collapse to appear.

我在setState中找不到任何运气...我正在componenetDidMount()中,componentDidMount()内部做所有的反应代码,有一个update()函数,在更新中有一个名为click的函数.,并在点击触发后执行:

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({折叠:!this.state.collapse});

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

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

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"?

代码:

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对象

Sorry if that's a lot of code, I deleted my var treeData which is a json object 100 lines long

推荐答案

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

You won’t get this context inside the regular function unless you bind this to the function or change it to arrow function

所以,改变

  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之外,并在构造函数中手动绑定为

Or move the function outside componentDidMount and do manual binding in constructor as

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

这篇关于在函数内部反应设置状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆