React Hooks - измененное состояние не отображается сразу

Я пытаюсь преобразовать класс в компонент без сохранения состояния с помощью ловушек React.

Сам компонент очень прост, и я не понимаю, где я делаю ошибку, так как это почти копипаст из документации по реакции.

Компонент показывает всплывающее окно, когда пользователь нажимает кнопку (кнопка передается через реквизиты моему компоненту). Пользуюсь typescript.

Я прокомментировал строку, которая не выполняет то, что я хочу, в версии для hooks

Вот мой оригинальный класс:

export interface NodeMenuProps extends PropsNodeButton {
  title?: string
  content?: JSX.Element
  button?: JSX.Element
}
export interface NodeMenuState {
  visible: boolean
}
export class NodeMenu extends React.Component<NodeMenuProps, NodeMenuState> {
  state = {
    visible: false
  }

  hide = () => {
    this.setState({
      visible: false
    })
  }

  handleVisibleChange = (visible: boolean) => {
    this.setState({ visible })
  }

  render() {        
    return (
      <div className = {this.props.className}>
        <div className = {styles.requestNodeMenuIcon}>
          <Popover
            content = {this.props.content}
            title = {this.props.title}
            trigger = "click"
            placement = "bottom"
            visible = {this.state.visible}
            onVisibleChange = {this.handleVisibleChange}
          >
            {this.props.button}
          </Popover>
        </div>
      </div>
    )
  }
}

Вот версия для React hooks:

export interface NodeMenuProps extends PropsNodeButton {
  title?: string
  content?: JSX.Element
  button?: JSX.Element
}    
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
  const [isVisible, setIsVisible] = useState(false)      

  const hide = () => {
    setIsVisible(false)
  }

  const handleVisibleChange = (visible: boolean) => {
    console.info(visible) // visible is `true` when user clicks. It works
    setIsVisible(visible) // This does not set isVisible to `true`.
    console.info(isVisible) // is always `false` despite `visible` being true.
  }      

  return (
    <div className = {props.className}>
      <div className = {styles.requestNodeMenuIcon}>
        <Popover
          content = {props.content}              
          title = {props.title}
          trigger = "click"
          placement = "bottom"
          visible = {isVisible}
          onVisibleChange = {handleVisibleChange}
        >
          {props.button}
        </Popover>
      </div>
    </div>
  )
}
visible - это константа, определенная в вашем компоненте. Невозможно, чтобы вызов функции любой мог изменить его значение.
Dan Abramov 22.11.2018 13:21

Вместо этого setVisible запускает повторный рендеринг. Когда мы снова выполним рендеринг, для него будет установлено новое значение.

Dan Abramov 22.11.2018 13:22

У меня такая же проблема, но мой jsx обновляется, а значение константы в моей функции нет :( @ DJ2

Usman Iqbal 31.08.2020 15:35
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
10
3
17 312
1

Ответы 1

Как и в случае с setState, поведение обновления состояния с использованием хуков также потребует повторного рендеринга и обновления, и, следовательно, изменение не будет сразу видно. Однако если вы попытаетесь записать состояние вне метода handleVisibleChange, вы увидите состояние обновления

export const NodeMenu: React.SFC<NodeMenuProps> = props => {
  const [isVisible, setIsVisible] = useState(false)      

  const hide = () => {
    setIsVisible(false)
  }

  const handleVisibleChange = (visible: boolean) => {
    console.info(visible) // visible is `true` when user clicks. It works
    setIsVisible(visible) // This does not set isVisible to `true`.
  }      

  console.info({ isVisible });
  return (
    <div className = {props.className}>
      <div className = {styles.requestNodeMenuIcon}>
        <Popover
          content = {props.content}              
          title = {props.title}
          trigger = "click"
          placement = "bottom"
          visible = {isVisible}
          onVisibleChange = {handleVisibleChange}
        >
          {props.button}
        </Popover>
      </div>
    </div>
  )
}

Любое действие, которое вам нужно предпринять в зависимости от того, было ли обновлено состояние, можно выполнить с помощью ловушки useEffect, например

useEffect(() => {
   // take action when isVisible Changed
}, [isVisible])

Спасибо, Шубхам, теперь я вижу, что значение обновляется. Однако, поскольку isVisible становится true при повторном рендеринге, я не понимаю, почему всплывающее окно не отображается. Я прочитал документацию об useEffect, но не понимаю, почему мне нужно использовать это для отображения всплывающего окна, если isVisible действительно меняется на true?

Greg Forel 22.11.2018 16:32

вам не нужно использовать useEffect. Это была просто дополнительная информация

Shubham Khatri 22.11.2018 17:05

@ShubhamKhatri означает ли это, что обработчик изменений также должен быть перемещен в ловушку useEffect?

DJ2 11.10.2019 21:56

Я тоже столкнулся с подобной проблемой, но не нашел решения.

Jeethesh Kotian 19.02.2021 08:32

Другие вопросы по теме