更新状态的正确位置 - React JS
Right place to update a state - React JS
我正在 React JS 中创建一个简单的滑块组件。我有三个按钮 Restart
、Previous
、Next
。单击上一个按钮会将当前状态减 1,并会一直持续到当前状态等于 0。此外,下一个按钮将使状态递增,直到等于 slides.length-1
。 Slider 对我来说工作正常,问题是当最后一张幻灯片接近时 'Next' 按钮仍然启用,但是当我单击它时,它会被禁用。预期的行为是当呈现最后一张幻灯片时,按钮应该被禁用,并且不需要额外的点击。上一个按钮也有同样的问题。
您可以在此处查看行为:https://codesandbox.io/s/react-live-sandbox-krfjk
我确定,更新状态存在一些问题,我可能在错误的地方更新了它,这就是我没有想到的。
您在单击 "prev" 按钮时也有相同的行为。与尝试计算禁用状态并将其存储在状态中相比,导出禁用状态可能更容易。
Slides.js 渲染函数
render() {
const { slides } = this.props;
return (
<div>
<div id="navigation">
<button
data-testid="button-restart"
onClick={this.resandler}
data-testid="button-restart">
Restart
</button>
<button
data-testid="button-prev"
onClick={this.prevHandler}
data-testid="button-prev"
// if current slide is 0, there is no previous
disabled={this.state.currentSlide === 0}>
Prev
</button>
<button
data-testid="button-next"
onClick={this.nextHandler}
data-testid="button-next"
// if current slide is slides.length - 1, there is no next
disabled={this.state.currentSlide === this.props.slides.length - 1}>
Next
</button>
</div>
{slides.map((slide, i) => {
return i === this.state.currentSlide ? (
<div id="slide" key={slide + i}>
<h1 data-testid="title">{slide.title}</h1>
<p data-testid="text">{slide.text}</p>
</div>
) : null;
})}
</div>
);
}
在您的 nextHandler()
中将 setState 更改为:
this.setState({
currentSlide: this.state.currentSlide + 1,
nextDisabled: this.state.currentSlide + 1 === this.props.slides.length - 1,
prevDisabled: false,
});
考虑到您的应用程序的简单性,您不需要 prevState - 您也不需要在 return 中定义每个状态字段(React 将隐式填充这些字段作为它们的最后一个值):
// This can be just prevState => since you aren't using props
this.setState((prevState, props) => {
if (prevState.currentSlide < this.props.slides.length - 1) {
return {
currentSlide: prevState.currentSlide + 1,
prevDisabled: false,
};
} else if (prevState.currentSlide === this.props.slides.length - 1) { // Issue is here
return {
nextDisabled: true,
prevDisabled: false, // Don't need to keep defining this
};
}
});
它不起作用的原因是您使用以下方法检查是否应禁用该按钮:
prevState.currentSlide === this.props.slides.length - 1
prevState 将比您预期的慢 1 次。您需要使用当前状态来执行此操作。所以另一个修复方法是将其更改为:
prevState.currentSlide + 1 === this.props.slides.length - 1
您可以对 prevHandler()
应用类似的修复。
您的代码中的问题是您在检查是否应禁用上一个或下一个按钮之前没有更新 currentSlide
。
当按下任何按钮时,首先更新 currentSlide
然后检查应启用或禁用哪个按钮。
nextHandler
函数应该如下所示
nextHandler() {
this.setState(
prevState => ({ currentSlide: ++prevState.currentSlide}),
() => {
if (this.state.currentSlide < this.props.slides.length - 1) {
this.setState({ prevDisabled: false });
} else {
this.setState({ nextDisabled: true });
}
}
);
}
和prevHandler
应该是这样的
prevHandler() {
this.setState(
prevState => ({ currentSlide: --prevState.currentSlide}),
() => {
if (this.state.currentSlide === 0) {
this.setState({ nextDisabled: false, prevDisabled: true });
}
}
);
}
我正在 React JS 中创建一个简单的滑块组件。我有三个按钮 Restart
、Previous
、Next
。单击上一个按钮会将当前状态减 1,并会一直持续到当前状态等于 0。此外,下一个按钮将使状态递增,直到等于 slides.length-1
。 Slider 对我来说工作正常,问题是当最后一张幻灯片接近时 'Next' 按钮仍然启用,但是当我单击它时,它会被禁用。预期的行为是当呈现最后一张幻灯片时,按钮应该被禁用,并且不需要额外的点击。上一个按钮也有同样的问题。
您可以在此处查看行为:https://codesandbox.io/s/react-live-sandbox-krfjk
我确定,更新状态存在一些问题,我可能在错误的地方更新了它,这就是我没有想到的。
您在单击 "prev" 按钮时也有相同的行为。与尝试计算禁用状态并将其存储在状态中相比,导出禁用状态可能更容易。
Slides.js 渲染函数
render() {
const { slides } = this.props;
return (
<div>
<div id="navigation">
<button
data-testid="button-restart"
onClick={this.resandler}
data-testid="button-restart">
Restart
</button>
<button
data-testid="button-prev"
onClick={this.prevHandler}
data-testid="button-prev"
// if current slide is 0, there is no previous
disabled={this.state.currentSlide === 0}>
Prev
</button>
<button
data-testid="button-next"
onClick={this.nextHandler}
data-testid="button-next"
// if current slide is slides.length - 1, there is no next
disabled={this.state.currentSlide === this.props.slides.length - 1}>
Next
</button>
</div>
{slides.map((slide, i) => {
return i === this.state.currentSlide ? (
<div id="slide" key={slide + i}>
<h1 data-testid="title">{slide.title}</h1>
<p data-testid="text">{slide.text}</p>
</div>
) : null;
})}
</div>
);
}
在您的 nextHandler()
中将 setState 更改为:
this.setState({
currentSlide: this.state.currentSlide + 1,
nextDisabled: this.state.currentSlide + 1 === this.props.slides.length - 1,
prevDisabled: false,
});
考虑到您的应用程序的简单性,您不需要 prevState - 您也不需要在 return 中定义每个状态字段(React 将隐式填充这些字段作为它们的最后一个值):
// This can be just prevState => since you aren't using props
this.setState((prevState, props) => {
if (prevState.currentSlide < this.props.slides.length - 1) {
return {
currentSlide: prevState.currentSlide + 1,
prevDisabled: false,
};
} else if (prevState.currentSlide === this.props.slides.length - 1) { // Issue is here
return {
nextDisabled: true,
prevDisabled: false, // Don't need to keep defining this
};
}
});
它不起作用的原因是您使用以下方法检查是否应禁用该按钮:
prevState.currentSlide === this.props.slides.length - 1
prevState 将比您预期的慢 1 次。您需要使用当前状态来执行此操作。所以另一个修复方法是将其更改为:
prevState.currentSlide + 1 === this.props.slides.length - 1
您可以对 prevHandler()
应用类似的修复。
您的代码中的问题是您在检查是否应禁用上一个或下一个按钮之前没有更新 currentSlide
。
当按下任何按钮时,首先更新 currentSlide
然后检查应启用或禁用哪个按钮。
nextHandler
函数应该如下所示
nextHandler() {
this.setState(
prevState => ({ currentSlide: ++prevState.currentSlide}),
() => {
if (this.state.currentSlide < this.props.slides.length - 1) {
this.setState({ prevDisabled: false });
} else {
this.setState({ nextDisabled: true });
}
}
);
}
和prevHandler
应该是这样的
prevHandler() {
this.setState(
prevState => ({ currentSlide: --prevState.currentSlide}),
() => {
if (this.state.currentSlide === 0) {
this.setState({ nextDisabled: false, prevDisabled: true });
}
}
);
}