react-fullpage - 避免渲染中的 setState 无限循环
react-fullpage - avoid setState infinite loop in render
TLDR 问题:基本上我想在页脚打开时隐藏 sidenav 按钮。
在我的 App.js
中,我正在呈现导航和 react-fullpage(滚动到部分组件)并传递 isFooterOpen 状态和更改它的方法。
App.js
class App extends Component {
state = { isFooterOpen: false };
show = () => { this.setState({ isFooterOpen: true }); };
hide = () => { this.setState({ isFooterOpen: false }); };
render() {
return (
<React.Fragment>
<Navigation
isFooterOpen={this.state.isFooterOpen}
hide={this.hide}
show={this.show}
/>
<FullPageWrapper
isFooterOpen={this.state.isFooterOpen}
hide={this.hide}
show={this.show}
{...fullpageOptions}
/>
</React.Fragment>
);
}
}
导航将状态向下传递到侧边按钮,我 show/hide 它基于它,工作正常。
问题是当我想从我的 FullpageWrapper 触发状态更改时,我正在检测我是滚动到上一节还是从上一节向上滚动。
组件正在使用渲染道具,所以基本上我在渲染中调用 setState,它会导致无限循环,但我找不到访问该状态(方向、索引等)的解决方法。甚至 toggleFooter 函数也感觉有点 "hacky" 因为我正在为那个状态对象设置属性,而不是用 npm ReactFullpage 组件以某种方式保持我自己的状态。
FullpageWrapper.js
function toggleFooter(state, props) {
if (state.callback === "onLeave") {
if (state.direction === "down") {
const emptySection = document.querySelector("#empty");
if (emptySection.classList.contains("active")) {
state.isFooterOpen = true;
// props.show(); // change app state and hide side button - infinite loop here
}
} else if (state.direction === "up" && state.origin.index === 5) {
state.isFooterOpen = false;
// props.hide(); // change app state and hide side button - infinite loop here
}
}
}
const FullPageWrapper = fullpageProps => (
<ReactFullpage
{...fullpageProps}
render={({ state, fullpageApi }) => {
toggleFooter(state, fullpageProps);
return (
<div style={{ position: "relative" }}>
<HeroSection />
<AboutSection />
<TeamSection />
<ServicesSection />
<ContactSection />
<Empty />
<Footer isFooterOpen={state.isFooterOpen} />
</div>
);
}}
/>
);
我也尝试了简单的事件总线,我从 FullpageWrapper 发送了一个事件,但我仍然从渲染器发送它,所以这是同样的问题...
我删除了所有不必要的内容,这里是 codesandbox 示例。
如果用 if
语句包装 setState
调用,我猜这会消除无限循环吗?
我在这里创建了一个更新的代码沙箱,看起来它的功能与您设计的一样:
https://codesandbox.io/s/p39w4z51pq
show = () => {
if(!this.state.isFooterOpen) {
this.setState({ isFooterOpen: true });
}
};
hide = () => {
if(this.state.isFooterOpen) {
this.setState({ isFooterOpen: false });
}
};
TLDR 问题:基本上我想在页脚打开时隐藏 sidenav 按钮。
在我的 App.js
中,我正在呈现导航和 react-fullpage(滚动到部分组件)并传递 isFooterOpen 状态和更改它的方法。
App.js
class App extends Component {
state = { isFooterOpen: false };
show = () => { this.setState({ isFooterOpen: true }); };
hide = () => { this.setState({ isFooterOpen: false }); };
render() {
return (
<React.Fragment>
<Navigation
isFooterOpen={this.state.isFooterOpen}
hide={this.hide}
show={this.show}
/>
<FullPageWrapper
isFooterOpen={this.state.isFooterOpen}
hide={this.hide}
show={this.show}
{...fullpageOptions}
/>
</React.Fragment>
);
}
}
导航将状态向下传递到侧边按钮,我 show/hide 它基于它,工作正常。
问题是当我想从我的 FullpageWrapper 触发状态更改时,我正在检测我是滚动到上一节还是从上一节向上滚动。
组件正在使用渲染道具,所以基本上我在渲染中调用 setState,它会导致无限循环,但我找不到访问该状态(方向、索引等)的解决方法。甚至 toggleFooter 函数也感觉有点 "hacky" 因为我正在为那个状态对象设置属性,而不是用 npm ReactFullpage 组件以某种方式保持我自己的状态。
FullpageWrapper.js
function toggleFooter(state, props) {
if (state.callback === "onLeave") {
if (state.direction === "down") {
const emptySection = document.querySelector("#empty");
if (emptySection.classList.contains("active")) {
state.isFooterOpen = true;
// props.show(); // change app state and hide side button - infinite loop here
}
} else if (state.direction === "up" && state.origin.index === 5) {
state.isFooterOpen = false;
// props.hide(); // change app state and hide side button - infinite loop here
}
}
}
const FullPageWrapper = fullpageProps => (
<ReactFullpage
{...fullpageProps}
render={({ state, fullpageApi }) => {
toggleFooter(state, fullpageProps);
return (
<div style={{ position: "relative" }}>
<HeroSection />
<AboutSection />
<TeamSection />
<ServicesSection />
<ContactSection />
<Empty />
<Footer isFooterOpen={state.isFooterOpen} />
</div>
);
}}
/>
);
我也尝试了简单的事件总线,我从 FullpageWrapper 发送了一个事件,但我仍然从渲染器发送它,所以这是同样的问题...
我删除了所有不必要的内容,这里是 codesandbox 示例。
如果用 if
语句包装 setState
调用,我猜这会消除无限循环吗?
我在这里创建了一个更新的代码沙箱,看起来它的功能与您设计的一样:
https://codesandbox.io/s/p39w4z51pq
show = () => {
if(!this.state.isFooterOpen) {
this.setState({ isFooterOpen: true });
}
};
hide = () => {
if(this.state.isFooterOpen) {
this.setState({ isFooterOpen: false });
}
};