最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ReactJS - Infinite loop, setState onChange method - Stack Overflow

programmeradmin5浏览0评论

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
Add a ment  | 

1 Answer 1

Reset to default 6

There 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.

发布评论

评论列表(0)

  1. 暂无评论