Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
435 views
in Technique[技术] by (71.8m points)

javascript - React, Uncaught RangeError: Maximum call stack size exceeded

I'm working in react and basically I want to make an button with tooltip, right now I'm making tooltip. I'm changing css display property in order to make it visible or not during mouse enter and leave. But there is an error and I don't know what to do...

Here is my code:

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

In console I'm getting this error:

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)

I can't find out what's wrong. I know it might be something about calling a function which in turn calls another function. But I can't see anything like this in my code and I'm not sure if it's all about it. Thanks for help :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem is you are calling setState from inside your render function. State changes should only happen as a result of something changing: user clicked on a button, the browser window was resized, a picture was taken, etc.

Never ever ever ever update the state while rendering (repeat that last sentence 20 times and never forget it).

Here is the problem code:

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

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

The above code would cause an infinite loop of sorts because setState causes render to be called. Since iconStyle and style are props, and props cannot change, you should use those props to build your initial state.

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

Later, if someone clicks a button and you want the iconStyle to change, you would create a click handler which updates your state:

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

This would cause your component to be rerendered and the new state would be reflected.

Think of your "state" as someone cooking and we are going to take photographs of them cooking. The initial state is "eggs cracked: no, flour poured: no, veggies chopped: no", and you take a picture of this state. Then the chef does something - cracks the eggs. The state has now changed, and you take a picture of it. Then she cuts the veggies. Again, the state has changed and you take a picture.

Each photograph in the analogy represents your "render" function - a snapshot of the "state" at a particular point in time. If every time you took a photograph the flour got poured, well we would have to take another picture because the flour was just poured. Taking another picture would cause more flour to get poured so we'd have to take another picture. Eventually you'd fill the kitchen to the ceiling with a celiac's nightmare and suffocate everybody in the room. You'd also run out of film or hard disk space on your camera.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...