2016-12-19 107 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

謝謝,並再次感謝您寶貴的答覆。 :) –

相關問題