2016-12-19 199 views
5

我正在处理反应,基本上我想用工具提示制作按钮,现在我正在提供工具提示。我正在更改css显示属性,以便在鼠标进入和离开时使其可见或不可见。但有一个错误,我不知道该怎么办......反应,未捕获RangeError:超出最大调用堆栈大小

这里是我的代码:

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) 

我无法找出问题所在。我知道这可能是关于调用一个函数,然后调用另一个函数。但我在代码中看不到任何这样的内容,我不确定它是否与它有关。感谢您的帮助:)

+8

永远,永远,在任何情况下......我不在乎你可能会想出什么为理由......永远不要叫'从'render'函数内部setState' ;)调用'setState'会导致rerender,这会导致调用'setState',导致rerender,然后调用'setState'并导致rerender,然后再调用'setState',然后您的组件被重新渲染,然后'setState'被再次调用,另一次重新移动...直到你的调用堆栈被最大化出 –

+1

@RyanWheale我希望我能够upvote那个评论一百万次:) – Icepickle

+0

谢谢,这是有道理的,我没有想过那 – Karol

回答

17

每当您看到代码从render函数中调用setState时,它应该会引起与人类蜈蚣电影相同类型的情绪。国家应改变只发生,因为事情变化的结果是:用户点击一个按钮,浏览器窗口大小被调整,拍摄照片等

这里的问题是代码:

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

这将导致您的组件被重新描绘和新的状态会被反映出来。

把你的“国家”看作是有人在做饭,我们会为他们拍照做饭。该初始状态是“鸡蛋破裂:没有,面粉倒:没有,蔬菜切碎:没有”,和你把这种状态的照片。然后厨师做了一些事情 - 把鸡蛋打碎。现在国家已经改变了,你拍了一张照片。然后,她切割蔬菜。国家已经改变了,你拍了一张照片。

类比中的每张照片都表示您的“渲染”功能 - 在特定时间点的“状态”快照。如果每次拍摄照片的时候面粉都倒了,那么我们就不得不拍摄另一张照片了,因为面粉刚刚倒了。再拍一张照片会导致更多的面粉倒掉,所以我们不得不拍摄另一张照片。最后,你会用腹腔的噩梦将厨房填满天花板,并窒息房间里的每个人。您的相机上还没有电影或硬盘空间。

+0

太好了,谢谢。但现在我',得到这个错误:1)警告:标记上的未知道具文本。从元素中删除此道具。 2)警告:不支持的样式属性background-color。你的意思是backgroundColor?检查'IconButton'的渲染方法。那些在 – Karol

+0

之前没有那些单独的问题,但应该很容易调试。我不确定“文本”道具 - 它看起来并不像你使用它。另外,反应中的样式必须使用JavaScript名称。基本上'background-color'变成'backgroundColor','border-width'变成'borderWidth'等。这是正常的反应。 –

+0

我给你的另一个提示是,你的工具提示的可见性应该是你的状态的一部分。最初,tooltipIsVisible应该是false。当用户点击按钮时,您应该调用setState并将该值设置为true。这样做会导致您的组件被重新渲染。在你的'render'函数中,你可以检查这个变量并相应地渲染工具提示。 –

4

感谢@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>

它的工作完美无瑕。 我希望我能帮助别人节省数小时的宝贵生命。

干杯:)

+1

啊,这和从渲染函数里调用'setState'基本上是一样的。接得好。 –

+0

谢谢,并再次感谢您宝贵的答复。 :) –

相关问题