状态值在条件 setState 中落后一步更新
State value is updated one step behind in conditional setState
我正在实现滑块组件。当用户单击向左或向右箭头时,它会按给定 scrollWidth
更改滚动值。这个实现有一个问题:
const Slider = (props) => {
const [scrollValue, setScrollValue] = useState(0)
const [containerDimensions, setWidths] = useState({ offsetWidth: 0, scrollWidth: 0 })
const [activeLeft, setActiveLeftArrow] = useState(false)
const [activeRight, setActiveRightArrow] = useState(true)
...
const checkArrowDisable = () => {
containerDimensions.offsetWidth + scrollValue < containerDimensions.scrollWidth ? setActiveRightArrow(true) : setActiveRightArrow(false)
scrollValue > 0 ? setActiveLeftArrow(true) : setActiveLeftArrow(false)
}
const scrollRight = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft += scrollWidth
setScrollValue(scrollValue + scrollWidth)
checkArrowDisable()
}
const scrollLeft = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft -= scrollWidth
setScrollValue(scrollValue - scrollWidth)
checkArrowDisable()
}
在 checkArrowDisable
中,滚动和容器宽度值被检查为 hide/show 左右箭头。问题是,在这个实现中,activeLeft
和 activeRight
的状态更新了一步。
checkArrowDisable
函数有什么问题?
编辑:
解决这个问题的关键是用新的更新值创建中间变量并将其传递给下一个函数。
const scrollRight = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft += scrollWidth
const updatedScrollValue = scrollValue + scrollWidth
setScrollValue(updatedScrollValue)
checkArrowDisable(updatedScrollValue)
}
然后
const checkArrowDisable = (newScrollValue) => {
containerDimensions.offsetWidth + newScrollValue < containerDimensions.scrollWidth ? setActiveRightArrow(true) : setActiveRightArrow(false)
newScrollValue > 0 ? setActiveLeftArrow(true) : setActiveLeftArrow(false)
}
二传手是异步的。所以你不应该在同一个函数或子函数中使用假设的设定值。我的意思是:
const scrollLeft = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft -= scrollWidth
setScrollValue(scrollValue - scrollWidth) # scrollvalue not necessarily updated yet
checkArrowDisable() # uses scrollvalue which is either updated or not
}
我建议为 scrollValue - scrollWidth
使用变量并传递给 checkArrowDisable
函数
您的 checkArrowDisable
函数不是必需的,因为这些单独的方法可以在每个 scroll
函数的一行中完成。
最好这样做:
const scrollRight = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft += scrollWidth
const newScrollValue = scrollValue - scrollWidth
setScrollValue(newScrollValue)
setActiveRightArrow(containerDimensions.offsetWidth + newScrollValue < containerDimensions.scrollWidth)
}
const scrollLeft = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft -= scrollWidth
const newScrollValue = scrollValue - scrollWidth
setScrollValue(newScrollValue)
setActiveLeftArrow(newScrollValue > 0)
}
问题是 useState
挂钩设置器 运行 是异步的。所以当你尝试在checkArrowDisable
中使用scrollValue
时,它仍然在使用更新之前的scrollValue
。
按照我上面的建议解决这个问题。
我正在实现滑块组件。当用户单击向左或向右箭头时,它会按给定 scrollWidth
更改滚动值。这个实现有一个问题:
const Slider = (props) => {
const [scrollValue, setScrollValue] = useState(0)
const [containerDimensions, setWidths] = useState({ offsetWidth: 0, scrollWidth: 0 })
const [activeLeft, setActiveLeftArrow] = useState(false)
const [activeRight, setActiveRightArrow] = useState(true)
...
const checkArrowDisable = () => {
containerDimensions.offsetWidth + scrollValue < containerDimensions.scrollWidth ? setActiveRightArrow(true) : setActiveRightArrow(false)
scrollValue > 0 ? setActiveLeftArrow(true) : setActiveLeftArrow(false)
}
const scrollRight = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft += scrollWidth
setScrollValue(scrollValue + scrollWidth)
checkArrowDisable()
}
const scrollLeft = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft -= scrollWidth
setScrollValue(scrollValue - scrollWidth)
checkArrowDisable()
}
在 checkArrowDisable
中,滚动和容器宽度值被检查为 hide/show 左右箭头。问题是,在这个实现中,activeLeft
和 activeRight
的状态更新了一步。
checkArrowDisable
函数有什么问题?
编辑:
解决这个问题的关键是用新的更新值创建中间变量并将其传递给下一个函数。
const scrollRight = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft += scrollWidth
const updatedScrollValue = scrollValue + scrollWidth
setScrollValue(updatedScrollValue)
checkArrowDisable(updatedScrollValue)
}
然后
const checkArrowDisable = (newScrollValue) => {
containerDimensions.offsetWidth + newScrollValue < containerDimensions.scrollWidth ? setActiveRightArrow(true) : setActiveRightArrow(false)
newScrollValue > 0 ? setActiveLeftArrow(true) : setActiveLeftArrow(false)
}
二传手是异步的。所以你不应该在同一个函数或子函数中使用假设的设定值。我的意思是:
const scrollLeft = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft -= scrollWidth
setScrollValue(scrollValue - scrollWidth) # scrollvalue not necessarily updated yet
checkArrowDisable() # uses scrollvalue which is either updated or not
}
我建议为 scrollValue - scrollWidth
使用变量并传递给 checkArrowDisable
函数
您的 checkArrowDisable
函数不是必需的,因为这些单独的方法可以在每个 scroll
函数的一行中完成。
最好这样做:
const scrollRight = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft += scrollWidth
const newScrollValue = scrollValue - scrollWidth
setScrollValue(newScrollValue)
setActiveRightArrow(containerDimensions.offsetWidth + newScrollValue < containerDimensions.scrollWidth)
}
const scrollLeft = () => {
const scrollWidth = sliderItem.current.offsetWidth
sliderContainer.current.scrollLeft -= scrollWidth
const newScrollValue = scrollValue - scrollWidth
setScrollValue(newScrollValue)
setActiveLeftArrow(newScrollValue > 0)
}
问题是 useState
挂钩设置器 运行 是异步的。所以当你尝试在checkArrowDisable
中使用scrollValue
时,它仍然在使用更新之前的scrollValue
。
按照我上面的建议解决这个问题。