【问题标题】:Maximum call stack size exceeded - Connected React Component超出最大调用堆栈大小 - 连接的反应组件
【发布时间】:2017-08-22 16:43:42
【问题描述】:

我一生都无法弄清楚为什么会出错:

超过最大调用堆栈大小

当此代码运行时。如果我注释掉:

const tabs = this.getTabs(breakpoints, panels, selectedTab);

错误消失了。我什至注释掉了其他 setState() 电话,试图缩小问题所在。

代码(去掉了多余的功能):

export default class SearchTabs extends Component {
  constructor() {
    super();
    this.state = {
      filters: null,
      filter: null,
      isDropdownOpen: false,
      selectedFilter: null,
    };

    this.getTabs = this.getTabs.bind(this);
    this.tabChanged = this.tabChanged.bind(this);
    this.setSelectedFilter = this.setSelectedFilter.bind(this);

    this.closeDropdown = this.closeDropdown.bind(this);
    this.openDropdown = this.openDropdown.bind(this);
  }

  componentDidMount() {
    const { panels } = this.props;
    if (!panels || !panels.members || panels.members.length === 0) {
      this.props.fetchSearch();
    }
  }


  getTabs(breakpoints, panels, selectedTab) {
    const tabs = panels.member.map((panel, idx) => {
      const { id: panelId, headline } = panel;
      const url = getHeaderLogo(panel, 50);
      const item = url ? <img src={url} alt={headline} /> : headline;

      const classname = classNames([
        searchResultsTheme.tabItem,
        (idx === selectedTab) ? searchResultsTheme.active : null,
      ]);

      this.setState({ filter: this.renderFilters(
        panel,
        breakpoints,
        this.setSelectedFilter,
        this.state.selectedFilter,
        this.state.isDropdownOpen,
      ) || null });

      return (
        <TabItem
          key={panelId}
          classname={`${classname} search-tab`}
          headline={headline}
          idx={idx}
          content={item}
          onclick={this.tabChanged(idx, headline)}
        />
      );
    });

    return tabs;
  }

  render() {
    const { panels, selectedTab } = this.props;

    if (!panels || panels.length === 0) return null;

    const tabs = this.getTabs(breakpoints, panels, selectedTab);

    return (
      <div className={searchResultsTheme.filters}>
        <ul className={`${searchResultsTheme.tabs} ft-search-tabs`}>{tabs}</ul>
        <div className={searchResultsTheme.dropdown}>{this.state.filter}</div>
      </div>
    );
  }
}

export const TabItem = ({ classname, content, onclick, key }) => (
  <li key={key} className={`${classname} tab-item`} onClick={onclick} >{content}</li>
);

【问题讨论】:

  • 您可能在componentWillUpdate 中调用setState 两次,根据文档,这是not allowed。每次尝试渲染组件时,您还会在 3 个不同的地方调用 setState。每次你调用setState,你的组件都会重新渲染。这将导致无限循环。
  • 老天,是的,我现在正在重构这段代码,一团糟。这就是我在重构过程中遇到的那种问题

标签: javascript reactjs ecmascript-6


【解决方案1】:

因为这个循环:

  render  ----->   getTabs  ----->  setState -----
    ^                                            |
    |                                            |
    |____________________________________________v

您正在从渲染中调用 getTabs 方法,并在其中执行 setStatesetState 将触发重新渲染,再次 getTabs ..... 无限循环

getTabs 方法中删除setState,它会起作用。

这里是另一个问题:

onclick={this.tabChanged(idx, headline)}

我们需要为onClick事件分配一个函数,我们不需要调用它,但是这里你调用的是那个方法,使用这个:

onclick={() => this.tabChanged(idx, headline)}

【讨论】:

  • 不是这样的,我试过在getTabs中注释掉setState,没有什么影响
  • 我注释掉了 并且它消失了......嗯
  • 如果我们在渲染中执行 setState,代码将无法工作,它会一直抛出错误:“超出最大调用堆栈大小”:)
  • 您可以调用该函数并返回 TabItems,但不要执行 setState,重新排列代码并在 componentDidMount 生命周期方法或任何事件内部等其他地方执行 setState。
  • 在这种情况下,请在componentWillMount 中执行此操作,如果需要,您也可以禁用它,请检查此how to disable
猜你喜欢
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 2015-10-24
  • 2015-12-29
  • 2017-12-27
  • 2020-12-06
  • 1970-01-01
  • 2017-10-12
相关资源
最近更新 更多