2016-12-19 12 views
5

私は反応していますし、基本的にはツールチップでボタンを作成したい、今はツールチップを作成しています。私はそれを表示するかどうかをマウスの入力と終了の間にするためにCSSの表示プロパティを変更しています。しかし、そこにエラーがあると私は何をすべきかわからない...React、Uncaught 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'を呼び出すと再レンダリングが発生し、' setState'が呼び出され、再レンダリングが実行され、 'setState'が呼び出され、再レンダリングが実行され、' setState'がまだ呼び出されてコンポーネントが再レンダリングされます。あなたの呼び出しスタックが最大になるまで、 'setState'が再び呼び出され、もう一度rerenderが呼び出されます –

+1

@ RyanWheale私は100万回そのコメントをupvoteできればいいと思っています:) – Icepickle

+0

ありがとう、私は考えなかったその – Karol

答えて

17

setStaterenderの機能の中から呼び出すコードを見ると、人間のムービームービーと同じ種類の感情を呼び起こすはずです。状態の変更は、何かの変化の結果として起こるべき:ユーザーがボタンをクリックすると、ブラウザウィンドウのサイズが変更された、写真が撮影された、など。ここ

は、問題のコードです:

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

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

[嘔吐私の口で]

setStaterenderが呼び出されるため、上記のコードは無限ループのソートを引き起こします。 iconStylestyleは小道具であり、小道具は変更できないため、これらの小道具を使用して初期状態を構築する必要があります。

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

誰かがボタンをクリックし、あなたがiconStyleを変更したい場合は、後で、あなたの状態を更新するクリックハンドラを作成します。

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

これはあなたのコンポーネントを再レンダリングすることが原因となり新しい状態が反映されます。

あなたの「国家」を誰かの料理と考えて、私たちは料理の写真を撮ります。 初期状態は「卵が割れない:みじん切りなし、野菜:なしを、小麦粉を注ぎないなし」を、そしてあなたは、この状態の写真を撮ります。その後、シェフは何かをする - 卵を砕く。状態は今変更され、あなたはそれの写真を撮る。それから彼女は野菜を切る。繰り返しますが、状態が変わり、あなたが写真を撮ります。

類似点の各写真は、特定の時点での「状態」のスナップショットである「レンダリング」機能を表しています。あなたが写真を撮るたびに、小麦粉が注がれたならば、小麦粉がちょうど注がれたので、私たちは別の写真を撮らなければならないでしょう。別の写真を撮ると、粉がもっと注ぎ込まれるので、別の写真を撮る必要があります。最終的には、セリアックの悪夢で天井にキッチンを埋め、部屋の誰もが窒息するでしょう。カメラのフィルムやハードディスクの空き容量もなくなります。

+0

本当にありがとうございます。しかし、今私は、このエラーを取得しています:1)警告:タグで不明な小文字の 'text'。この小道具を要素から取り外します。 2)警告:サポートされていないスタイルプロパティbackground-color。 backgroundColorを意味しましたか? 'IconButton'のレンダリングメソッドを確認してください。それらは前にはなかった – Karol

+0

それらは別々の問題ですが、デバッグするのは簡単なはずです。私はあなたがそれを使用しているように見えない "テキスト"小道具についてはわかりません。また、反応のスタイルにはjavascript名を使用する必要があります。基本的に 'background-color'は' backgroundColor'になり、 'border-width'は' borderWidth'になります。これは普通の反応です。 –

+0

もう一つのヒントは、あなたのツールチップの可視性があなたの状態の一部であることです。最初は、tooltipIsVisibleはfalseにする必要があります。ユーザーがボタンをクリックすると、setStateを呼び出して値をtrueに設定する必要があります。そうすると、コンポーネントが再レンダリングされます。あなたの 'render'関数の中で、この変数をチェックし、それに応じてツールチップをレンダリングします。 –

4

@RyanWhealeのおかげで私は間違いに気付きました。

私のレンダー機能では、特定の状態を変更した機能を呼び出すボタン要素を返していました。

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

だから、私は私のミスは、私は、誤って、this.edit後に括弧を入力したことで、:

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

そして、私のedit機能は、いくつかの状態を変更し、次のようになります。返されたボタンは、このように見えました混乱が起こった。私は

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

代わりの

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

を書いたとき今、それが完璧に働きました。 私は、誰かが貴重な人生の時間を節約できるように願っています。

乾杯:)

+1

ああ、本質的には、レンダリング関数内から 'setState'を呼び出すのと同じことです。良いキャッチ。 –

+0

おかげさまで、ありがとうございました。貴重なご回答をいただき、ありがとうございます。 :) –

関連する問題