React,Uncaught RangeError:超出最大调用堆栈大小

新手上路,请多包涵

我正在做反应,基本上我想制作一个带有工具提示的按钮,现在我正在制作工具提示。我正在更改 css 显示属性,以便在鼠标进入和离开期间使其可见或不可见。但是有一个错误,我不知道该怎么办……

这是我的代码:

 import React from 'react';
import ReactDOM from 'react-dom';
import Style from 'style-it';
var Ink = require('react-ink');
import FontIcon from '../FontIcon/FontIcon';

var IconButton = React.createClass({

  getInitialState() {
      return {
          iconStyle: "",
          style: "",
          cursorPos: {},
      };
  },

  extend(obj, src) {
      Object.keys(src).forEach(function(key) { obj[key] = src[key]; });
      return obj;
  },

    Tooltip(props) {

        var style = {};

        if (this.tooltipDisplay) {
            style.display = "block";
        } else if (!this.tooltipDisplay) {
            style.display = "none";
        };

        return <div className="tooltip" style={style}>{_props.tooltip}</div>;
    },

    showTooltip(){
        this.tooltipDisplay = true;
    },

    removeTooltip(){
        this.tooltipDisplay = false;
    },

  render() {

    var _props = this.props,
      tooltip = this.Tooltip,
      opts,
      tooltipDisplay = false,
      disabled = false,
      rippleOpacity,
        outterStyleMy = {
        border: "none",
            outline: "none",
            padding: "8px 10px",
        "background-color": "red",
        "border-radius": 100 + "%",
        cursor: "pointer",
        },
        iconStyleMy = {
            "font-size": 12 + "px",
            "text-decoration": "none",
            "text-align": "center",
            display: 'flex',
            'justify-content': 'center',
            'align-items': 'center',
        },
      rippleStyle = {
        color: "rgba(0,0,0,0.5)",
      };

    if (_props.disabled || _props.disableTouchRipple) {
      rippleStyle.opacity = 0;
    };

    this.setState({
      iconStyle: _props.iconStyle
    });

    this.setState({
      style: _props.style
    });

    if (_props.disabled) {
       disabled = true;
    };

    if (this.state.labelStyle) {
        iconStyleMy = this.state.iconStyle;
    };

    if (this.state.style) {
      outterStyleMy = this.state.style;
    };

    if (_props.href) {
      opts.href = _props.href;
    };

        var buttonStyle = this.extend(outterStyleMy, iconStyleMy);

        return(
        <Style>
        {`
          .IconButton{
            position: relative;
          }
          .IconButton:disabled{
            color: ${_props.disabledColor};
          }
          .btnhref{
            text-decoration: none;
          }
        `}
         <a {...opts} className="btnhref" >
          <tooltip text={this.props.tooltip} position={this.options} />
          <button ref="button" className={"IconButton" + _props.className} disabled={disabled} style={buttonStyle}
          onMouseEnter={this.showTooltip} onMouseLeave={this.removeTooltip} >
            <Ink background={true} style={rippleStyle} opacity={rippleOpacity} />
            <FontIcon className={_props.iconClassName}/>
          </button>
        </a>
        </Style>
        );

  }
});

ReactDOM.render(
 <IconButton href="" className="" iconStyle="" style="" iconClassName="face" disabled="" disableTouchRipple="" tooltip="aaaaa" />,
 document.getElementById('app')
);

在控制台中,我收到此错误:

 Uncaught RangeError: Maximum call stack size exceeded
at defineRefPropWarningGetter (App.js:1053)
at Object.ReactElement.createElement (App.js:1220)
at Object.createElement (App.js:3329)
at Constructor.render (App.js:43403)
at App.js:15952
at measureLifeCyclePerf (App.js:15233)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (App.js:15951)
at ReactCompositeComponentWrapper._renderValidatedComponent (App.js:15978)
at ReactCompositeComponentWrapper._updateRenderedComponent (App.js:15902)
at ReactCompositeComponentWrapper._performComponentUpdate (App.js:15880)

我不知道出了什么问题。我知道这可能是关于调用一个函数,该函数又调用另一个函数。但是我在我的代码中看不到这样的东西,我不确定是否就是这样。感谢帮助 :)

原文由 Karol 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 422
2 个回答

问题是您从渲染函数内部调用 setState 。状态变化只应在发生某些变化时发生:用户单击按钮、调整浏览器窗口大小、拍摄照片等。

永远不要在渲染时更新状态(将最后一句话重复 20 次,永远不要忘记)。

这是问题代码:

 render () {
    ...
    this.setState({
      iconStyle: _props.iconStyle
    });

    this.setState({
      style: _props.style
    });
    ...
}

上面的代码会导致无限循环,因为 setState 导致 render 被调用。由于 iconStylestyle 是道具,道具不能改变,你应该使用这些道具来建立你的初始状态。

 getInitialState() {
  return {
      iconStyle: this.props.iconStyle,
      style: this.props.style,
      cursorPos: {},
  };
}

稍后,如果有人单击按钮并且您希望 iconStyle 更改,您将创建一个单击处理程序来更新您的状态:

 handleClick () {
  this.setState({
    iconStyle: 'clicked'
  });
}

这将导致您的组件被重新渲染并反映新的状态。

将您的“状态”想象成正在做饭的人,我们将拍摄他们做饭的照片。 初始状态 是“鸡蛋打碎: 没有,面粉倒了: 没有,蔬菜切碎: 没有”,你把这个状态拍下来。然后厨师做了一些事情——敲鸡蛋。现在状态已经改变了,你给它拍张照片。然后她切蔬菜。再一次,状态发生了变化,你拍了一张照片。

类比中的每张照片都代表您的“渲染”功能——特定时间点“状态”的快照。如果每次你拍一张照片,面粉都倒了,那么我们就得再拍一张,因为面粉刚刚倒了。再拍一张照片会导致倒更多的面粉,所以我们不得不再拍一张照片。最终,你会让厨房充满乳糜泻的噩梦,让房间里的每个人都窒息。您的相机上的胶片或硬盘空间也会用完。

原文由 Ryan Wheale 发布,翻译遵循 CC BY-SA 4.0 许可协议

感谢@RyanWheale,我注意到了我的错误。

在我的渲染函数中,我返回了一个按钮元素,它调用了一个改变特定状态的函数。返回的按钮看起来像这样:

 <button onclick={this.edit()} className="button-primary">Edit</button>

而我的 edit 函数改变了一些状态,看起来像这样:

 edit: function () {
    this.setState({editing: true});
}

所以,我的错误是我不小心在 this.edit 之后输入了括号。所以,当按钮元素被渲染时,编辑函数实际上被调用了,混乱发生了。现在,当我写

<button onclick={this.edit} className="button-primary">Edit</button>

代替

<button onclick={this.edit()} className="button-primary">Edit</button>

它完美地工作。我希望我能帮助某人挽救他宝贵的生命。

干杯 :)

原文由 Filip Savic 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题