Значение состояния обновляется на один шаг в условном наборе setState - PullRequest
0 голосов
/ 19 апреля 2020

Я реализую компонент слайдера. Когда пользователь нажимает стрелку влево или вправо, он меняет значение прокрутки на 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 значения прокрутки и ширины контейнера проверяются, чтобы скрыть / показать стрелку влево и вправо. Проблема в том, что в этой реализации состояния 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)
  }

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

Сеттеры асин c. Поэтому не следует использовать предполагаемое установленное значение в той же функции или подфункции. Я имею в виду:

  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

0 голосов
/ 19 апреля 2020

Ваша 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 установщики хуков работают асинхронно. Поэтому, когда вы пытались использовать scrollValue в checkArrowDisable, он все еще использовал предыдущий scrollValue до его обновления.

Выполнение того, что я рекомендую выше, решает эту проблему.

...