如何从无限重新渲染中停止反应组件
Posted
技术标签:
【中文标题】如何从无限重新渲染中停止反应组件【英文标题】: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 用于“语言”以及导致无限重新渲染的原因? 【参考方案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中阻塞重新渲染并且不了解问题。以上是关于如何从无限重新渲染中停止反应组件的主要内容,如果未能解决你的问题,请参考以下文章
在 history.push 反应之后如何停止重新加载整个组件