React:基于onFocus更新嵌套组件状态,"超出最大调用堆栈大小"错误

时间:2017-02-13 15:12:04

标签: javascript reactjs meteor

我有一个带有以下结构中组件的反应应用程序:

<App>
    <Toolbar this.state={sectionInFocus: someSectionID }/>
    <Chart>
       <Section> <input value=someSectionID /> <Section />
       <Section> <input value=someSectionID  /> <Section />
       <Section> <input value=someSectionID  /> <Section />
       ...more sections...
    </Chart>
</App>

我希望采用一种功能,当部分中的输入按钮聚焦于(onFocus)时,工具栏的状态会被设置。

如何将工具栏的状态设置为上次选定部分的ID?我是否在每个部分设置状态,然后向后传递2个级别到工具栏?

我试图至少将根组件中的状态设置为聚焦的sectionID,但现在我收到另一条错误消息(达到最大调用堆栈),如下所示:

App.js:

import React, { Component } from 'react';
import Chart from './chart';

export default class App extends Component {

  constructor(props){
    super(props)
    this.state = {
      sectionInFocus: ''
    }
  }

  componentDidUpdate(){
    console.log(this.state); // maximum call stack size exceeded
  }

  chartUpdate(obj){
    const { sectionInFocus } = obj;
    console.log(sectionInFocus);
    this.setState({ sectionInFocus });
  }

  render() {
    return (
    <div>
      <Chart chart={{"chartData":["abc","def","ghi"]}} onUpdate={this.chartUpdate.bind(this)}/>
    </div>
    )
  }

};

chart.js之

import React, { Component } from 'react';
import Section from './section';

export default class Chart extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sectionInFocus: ""
    }
  }

  componentDidUpdate(){
    console.log(this.state.sectionInFocus);
    this.props.onUpdate(this.state);
  }

  sectionUpdate(sectionID) {
    this.setState({sectionInFocus: sectionID});
  }

  renderSections(chartData) {
    return chartData.map((section) => {
      return (
        <Section
          key = {section}
          sectionID = {section}
          onUpdate={this.sectionUpdate.bind(this)}
        />
      )
    })
  }

  render(){
    let chartData = this.props.chart.chartData;
    return (
      <div>
        {this.renderSections(chartData)}
      </div>
    )
  }
}

Section.js

import React, { Component } from 'react';

export default class Section extends Component {
  updateParentState(){
    this.props.onUpdate(this.props.sectionID)
  }
  render(){
    return (
      <div>
        <input
          value={this.props.sectionID}
          onFocus={this.updateParentState.bind(this)}
        />
      </div>
    )
  }
}

我收到最大调用堆栈错误消息的错误是什么?有没有更简单的方法来处理这种功能,还是这种做事的反应方式?我是否应该考虑使用redux来有效地管理它?

非常感谢您提供的任何帮助!

1 个答案:

答案 0 :(得分:1)

  

我是否在每个部分设置状态,然后向后传递2个级别   工具栏?

没有

  

如何将工具栏的状态设置为上次选择的ID   部?

您应该只为sectionInFocus数据提供一个事实来源。这意味着无论您的组件有多少父项,您都应该只在最高根组件中设置状态(需要使用数据的最高级别)。在您的情况下,它是App组件(最好是像Redux一样拥有状态管理,但现在这个问题超出了这个问题。)

所以你应该这样做:

App.js:

import React, { Component } from 'react';
import Chart from './chart';

export default class App extends Component {

  constructor(props){
    super(props)
    this.state = {
      sectionInFocus: ''
    }
    this.chartUpdate = this.chartUpdate.bind(this);
  }

  componentDidUpdate(){
    console.log(this.state); // maximum call stack size exceeded
  }

  chartUpdate(obj){
    const { sectionInFocus } = obj;
    console.log(sectionInFocus);
    this.setState({ sectionInFocus });
  }

  render() {
    return (
    <div>
      <Chart chart={{"chartData":["abc","def","ghi"]}} onUpdate={this.chartUpdate}/>
    </div>
    )
  }

};

chart.js之

import React, { Component } from 'react';
import Section from './section';

export default class Chart extends Component {

  renderSections(chartData) {
    return chartData.map((section) => {
      return (
        <Section
          key = {section}
          sectionID = {section}
          onUpdate={this.props.sectionUpdate}
        />
      )
    })
  }

  render(){
    let chartData = this.props.chart.chartData;
    return (
      <div>
        {this.renderSections(chartData)}
      </div>
    )
  }
}

Section.js

import React, { Component } from 'react';

export default class Section extends Component {
  render(){
    return (
      <div>
        <input
          value={this.props.sectionID}
          onFocus={() => this.props.onUpdate(this.props.sectionID)}
        />
      </div>
    )
  }
}