繁体   English   中英

如何停止对组件进行无限重渲染

[英]How to stop react component from infinite re-render

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

我得到的错误是:setState(...):在现有状态转换期间无法更新...

我刚刚使用了shouldComponentUpdate,但它导致click事件无法正常工作。

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

有谁知道其他解决方案,而不是组件更新来阻止组件无限重新渲染吗?

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);

我发现了组件继续重新渲染的原因,实际上是由于以下条件造成的:

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

这始终是正确的,并且获取路径并推送到导致组件重新渲染的路径。

谢谢

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。这就是为什么要重新渲染。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM