React, Uncound RangeError: Maximum Call Stack Size Exceeded

I work in response, and basically want to create a tooltip button, now I'm doing a tooltip. I am changing the css display property to make it visible or not during mouse input and output. But there is a mistake, and I do not 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 the console, I get 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 understand what happened. I know this could be something like calling a function, which in turn calls another function. But I don’t see anything like this in my code, and I’m not sure if everything is about it. Thanks for the help:)

+5
source share
2 answers

Whenever you see code that calls setState from within the render function, it should trigger the same emotions as a centipede in a person. State changes should only occur as a result of something: the user clicked a button, the browser window size changed, a photo was taken, etc.

Here is the problem code:

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

[tear in the mouth]

The above code will cause an infinite loop because setState calls the render call. Since iconStyle and style are details and the details cannot be changed, you must use these details to create your initial state.

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

Later, if someone clicks the button and you want to change the icon, you must create a click handler that updates your state:

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

This will cause your component to restart and the new state will be reflected.

Think of your “state” as how someone cooks, and we are going to photograph them. initial state : "eggs are cracked: no , flour spills: no , veggies chopped: no " and you take a picture of this state. Then the chef does something - crack the eggs. Now the state has changed, and you will take a picture of it. Then she cuts the vegetables. Again, the state has changed, and you take a picture.

Each photo in analogy represents your "rendering" function - a snapshot of the "state" at a specific point in time. If every time you took a photograph, the flour poured out, we would need to take another photograph, because it just spilled into the flour. Another picture will make more flour pour out, so we will need to take another photo. In the end, you would fill the kitchen to the ceiling with a nightmare and strangle everyone in the room. You will also have a shortage of film or hard disk space on your camera.

+17
source

Thanks to @RyanWheale, I noticed my mistake.

In my rendering function, I was returning a button element that called a function that changed a certain state. The returned button looked like this:

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

And my edit function changes some state and looks like this:

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

So, I am mistaken in that I accidentally typed the brackets after this.edit , so there was chaos. Now that i wrote

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

instead

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

he worked flawlessly. Hope I help someone save the hours of their precious life.

Greetings :)

+4
source

Source: https://habr.com/ru/post/1261522/


All Articles