I'm creating a ponent using codemirror but seems that something in my code is wrong because when I try to update the state of my main ponent the applications breaks the browser, my research is pointing to a infinite loop at least I can see that when I'm trying to debug.
I hope someone of you can help me with this issue, maybe was my fault, thanks.
my main ponent:
import React, { Component, PropTypes } from 'react';
import Editor from '../editor';
import Preview from '../preview';
class Playground extends Component {
constructor(props) {
super(props);
this.state = {
code: 'Hi I am a ponent',
newCode: ''
};
this.handleCodeChange = this.handleCodeChange.bind(this);
}
handleCodeChange(code) {
// Everything works fine until this step, when the ponent wants to update the state, start the infinite loop
this.setState({ newCode: code });
}
loadCode(code) {
this.refs.editor.setCode(code);
}
render() {
return (
<div>
<Editor
ref='editor'
codeText={this.state.code}
onChange={this.handleCodeChange}
/>
<Preview code={this.state.newCode} />
</div>
);
}
}
Playground.propTypes = {
ponent: PropTypes.string
};
export default Playground;
my editor ponent:
import React, { Component, PropTypes } from 'react';
import style from './style';
import CodeMirror from 'codemirror';
import 'codemirror/mode/javascript/javascript';
class Editor extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
ponentDidMount() {
this.editor = CodeMirror.fromTextArea(this.refs.editor, {
lineNumbers: this.props.lineNumbers,
matchBrackets: true,
mode: 'javascript',
readOnly: this.props.readOnly,
smartIndent: false,
tabSize: this.props.tabSize,
theme: this.props.theme
});
this.editor.on('change', this.handleChange);
}
ponentDidUpdate() {
if ( !this.props.readOnly ) {
this.editor.setValue(this.props.codeText);
}
}
handleChange() {
if ( !this.props.readOnly && this.props.onChange ) {
this.props.onChange(this.editor.getValue());
}
}
render() {
let _className = style.editor;
return (
<div className={ _className }>
<textarea ref="editor" defaultValue={this.props.codeText} />
</div>
);
}
}
Editor.propTypes = {
className: React.PropTypes.string,
codeText: PropTypes.string,
lineNumbers: PropTypes.bool,
onChange: PropTypes.func,
readOnly: PropTypes.bool,
tabSize: PropTypes.number,
theme: PropTypes.string
};
Editor.defaultProps = {
className: '',
lineNumbers: false,
readOnly: false,
tabSize: 2,
theme: 'one-dark'
};
export default Editor;
my preview ponent
import React, { Component, PropTypes } from 'react';
class Preview extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>{this.props.code}</div>
);
}
}
Preview.propTypes = {
code: PropTypes.string
};
export default Preview;
Let me know if you need more info or something else.
Thanks in advance.
Solution
I removed this snippet from the editor ponent
ponentDidUpdate() {
if ( !this.props.readOnly ) {
this.editor.setValue(this.props.codeText);
}
}
The reason is because this method set a new value to the editor that means update, then the process start again infinitely, this method can be used if you are loading the content of the editor manually, that is not my case.
Thanks Anthony
I'm creating a ponent using codemirror but seems that something in my code is wrong because when I try to update the state of my main ponent the applications breaks the browser, my research is pointing to a infinite loop at least I can see that when I'm trying to debug.
I hope someone of you can help me with this issue, maybe was my fault, thanks.
my main ponent:
import React, { Component, PropTypes } from 'react';
import Editor from '../editor';
import Preview from '../preview';
class Playground extends Component {
constructor(props) {
super(props);
this.state = {
code: 'Hi I am a ponent',
newCode: ''
};
this.handleCodeChange = this.handleCodeChange.bind(this);
}
handleCodeChange(code) {
// Everything works fine until this step, when the ponent wants to update the state, start the infinite loop
this.setState({ newCode: code });
}
loadCode(code) {
this.refs.editor.setCode(code);
}
render() {
return (
<div>
<Editor
ref='editor'
codeText={this.state.code}
onChange={this.handleCodeChange}
/>
<Preview code={this.state.newCode} />
</div>
);
}
}
Playground.propTypes = {
ponent: PropTypes.string
};
export default Playground;
my editor ponent:
import React, { Component, PropTypes } from 'react';
import style from './style';
import CodeMirror from 'codemirror';
import 'codemirror/mode/javascript/javascript';
class Editor extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
ponentDidMount() {
this.editor = CodeMirror.fromTextArea(this.refs.editor, {
lineNumbers: this.props.lineNumbers,
matchBrackets: true,
mode: 'javascript',
readOnly: this.props.readOnly,
smartIndent: false,
tabSize: this.props.tabSize,
theme: this.props.theme
});
this.editor.on('change', this.handleChange);
}
ponentDidUpdate() {
if ( !this.props.readOnly ) {
this.editor.setValue(this.props.codeText);
}
}
handleChange() {
if ( !this.props.readOnly && this.props.onChange ) {
this.props.onChange(this.editor.getValue());
}
}
render() {
let _className = style.editor;
return (
<div className={ _className }>
<textarea ref="editor" defaultValue={this.props.codeText} />
</div>
);
}
}
Editor.propTypes = {
className: React.PropTypes.string,
codeText: PropTypes.string,
lineNumbers: PropTypes.bool,
onChange: PropTypes.func,
readOnly: PropTypes.bool,
tabSize: PropTypes.number,
theme: PropTypes.string
};
Editor.defaultProps = {
className: '',
lineNumbers: false,
readOnly: false,
tabSize: 2,
theme: 'one-dark'
};
export default Editor;
my preview ponent
import React, { Component, PropTypes } from 'react';
class Preview extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>{this.props.code}</div>
);
}
}
Preview.propTypes = {
code: PropTypes.string
};
export default Preview;
Let me know if you need more info or something else.
Thanks in advance.
Solution
I removed this snippet from the editor ponent
ponentDidUpdate() {
if ( !this.props.readOnly ) {
this.editor.setValue(this.props.codeText);
}
}
The reason is because this method set a new value to the editor that means update, then the process start again infinitely, this method can be used if you are loading the content of the editor manually, that is not my case.
Thanks Anthony
Share Improve this question edited Aug 24, 2016 at 10:56 Ulises García asked Aug 24, 2016 at 10:11 Ulises GarcíaUlises García 851 gold badge1 silver badge8 bronze badges 2-
what is the purpose of this code
this.handleCodeChange = this.handleCodeChange.bind(this);
, try removing it – Gopinath Shiva Commented Aug 24, 2016 at 10:26 - Please check out react-codemirror2 for usage with React – scniro Commented Oct 18, 2017 at 18:19
1 Answer
Reset to default 6There is an infinite loop because you call this.handleChange
in your editor ponent when a change occurs in the CodeMirror instance. When you call this.handleChange
at this moment, you update the state of your main ponent.
Then, when you update the main ponent state, it calls the ponentDidUpdate
function of your editor ponent. You set the value of the CodeMirror instance, which fires the change
event, updates the main ponent state, and so on.
To avoid this behavior, just make parisons of codeText
in ponentDidUpdate
and handleChange
to update only when it's necessary.