【问题标题】:How to stop react component from infinite re-render如何从无限重新渲染中停止反应组件
【发布时间】:2019-11-30 15:48:13
【问题描述】:

我想在我的应用程序中使用 js-cookie,但是当我获得 cookie 时,我的组件会不断重新渲染,直到浏览器崩溃。

我得到的错误是:setState(...): Cannot update during an existing state transition ...

我刚刚使用了 shouldComponentUpdate 但它导致点击事件不起作用。

shouldComponentUpdate(nextProps, nextState) 
{
    return nextState.language != this.state.language;
}

有没有人知道除了 shouldComponentUpdate 之外的任何其他解决方案来阻止组件无限重新渲染?

class MainLayout extends Component {
  constructor(props) {
    super(props);
    console.log('constructor');
    this.state = {
      sideBarOpen: false,
      languages: getStoreLanguages,
      language: Cookies.get('langCode')
    }
  }

  componentWillMount() {
    this.props.langCode();
    this.props.defaultLangCode();
  }

  componentDidMount() {
    $('.dropdown-toggle').megaMenu && $('.dropdown-toggle').megaMenu({ container: '.mmd' });
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextState.language != this.state.language;
  }

  toggleSidebar = () => {
    this.setState({
      sideBarOpen: !this.state.sideBarOpen,
    });
  }

  overlayClickHandler = () => {
    this.setState({
      sideBarOpen: false,
    });
  }

  handleLanguage = (langCode) => {
    if (Cookies.get('langCode')) {
      return Cookies.get('langCode');
    } else {
      Cookies.set('langCode', langCode, { expires: 7 });
      return langCode;
    }
  }

  render() {
    let overlay = { display: this.state.sideBarOpen ? 'block' : 'none' };
    const langCode = this.handleLanguage(this.props.params.id);
    const isDefaultLang = isDefaultLanguage(langCode);
    const isValidLang = isValidLanguage(langCode);

    if (langCode && !isValidLang) {
      this.props.router.push(`/${langCode}/error`);
    }

    if (langCode && isValidLang) {
      const path = getLocalisedPath(langCode, isDefaultLang)
      this.props.router.push("/" + path);
    }

    return (
      <div>
        <Helmet>
          <script type="application/ld+json">{structuredData()}</script>
        </Helmet>
        <TokenManager>
          {(state, methods) => (
            <div>
              <WithHelmet {...this.props} />
              <WithUserHeaderInfo {...this.props} />
              <WithStoreDetail />
              <WithDataLayerStoreDetail />
              <header className='header__nav'>
                <NavbarManagerWillHideOnEditor
                  sideBarOpen={this.state.sideBarOpen}
                  toggleSidebar={this.toggleSidebar}
                  languages={this.state.languages}
                  {...this.props}
                />
                <div
                  className="mmm__overlay"
                  onClick={this.overlayClickHandler}
                  style={overlay}
                />
                <div
                  className="mmm__overlay--hidenav"
                  onClick={this.overlayClickHandler}
                  style={overlay}
                />
              </header>
              <main>{this.props.children}</main>
              <Modal modalId="modal-account" size="md">
                {(closeModal) => (
                  <Auth
                    closeModal={closeModal} />
                )}

              </Modal>
              {!this.props.location.pathname.startsWith('/checkout') && <FooterWillHideOnEditor languages={this.state.languages}/>}
            </div>
          )
          }
        </TokenManager>
      </div>
    );
  }
}

const mapDispatchToProps = (dispatch, value) => {
  const langCode = Cookies.get('langCode') || value.params.id;
  const defaultLang = getDefaultLanguage();
  const isDefault = isDefaultLanguage(langCode);
  const isValid = isValidLanguage(langCode);
  const lang = !isValid || isDefault ? defaultLang : langCode;

  return {
    langCode: () => dispatch({ type: 'SET_LANGUAGE', payload: lang }),
    defaultLangCode: () => dispatch({ type: 'SET_DEFAULT_LANGUAGE', payload: defaultLang })
  }
}

export default connect(null, mapDispatchToProps)(MainLayout);

【问题讨论】:

  • 你需要展示你如何更新状态以及为什么......我们可以为它找出一个替代解决方案。没有它,我们无法通过提供的代码找出问题所在..!
  • @Armin : 你能在这里写下你的组件的一般结构吗?
  • @Panther 我已经用代码更新了帖子。谢谢
  • @sanji_mika 我在这里写了代码谢谢
  • @ArminSaeedi:我有一个问题:哪个原因使您的组件无限重新渲染?我看到您将 setState 用于“sideBarOpen”,但没有用于状态“语言”,您将 setState 用于“语言”以及导致无限重新渲染的原因?

标签: reactjs


【解决方案1】:
let overlay = { display: this.state.sideBarOpen ? 'block' : 'none' };
const langCode = this.handleLanguage(this.props.params.id);
const isDefaultLang = isDefaultLanguage(langCode);
const isValidLang = isValidLanguage(langCode);

if (langCode && !isValidLang) {
  this.props.router.push(`/${langCode}/error`);
}

if (langCode && isValidLang) {
  const path = getLocalisedPath(langCode, isDefaultLang)
  this.props.router.push("/" + path);
}

这里的代码正在重置 state/ 或 mapDispatchToProps 再次调度。这就是它重新渲染的原因。

【讨论】:

    【解决方案2】:

    我找到了组件不断重新渲染的原因,实际上是因为:

    if (langCode && isValidLang) {
        const path = getLocalisedPath(langCode, isDefaultLang)
        this.props.router.push("/" + path);
    }
    

    始终为真,获取路径并推送到导致组件重新渲染的路由。

    谢谢

    【讨论】:

    • 恭喜!我说你找到导致重新渲染异常的原因,这对于像这样解决这个问题非常重要。之后,你必须首先找到主要原因(例如通过console.log()),而不是在shouldComponentUpdate中阻塞重新渲染并且不了解问题。
    猜你喜欢
    • 2020-12-07
    • 1970-01-01
    • 2020-06-28
    • 2022-01-21
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2022-11-07
    • 2019-07-27
    相关资源
    最近更新 更多