web-dev-qa-db-fra.com

React Hooks - État modifié ne reflétant pas immédiatement

J'essaie de refactoriser une classe dans un composant sans état en utilisant des crochets React.

Le composant lui-même est très simple et je ne vois pas où je fais une erreur, car il s'agit presque d'un copier-coller des documents React.

Le composant affiche une fenêtre contextuelle lorsque l'utilisateur clique sur un bouton (le bouton est transmis via les accessoires à mon composant). J'utilise TypeScript.

J'ai commenté la ligne qui ne fait pas ce que je veux dans la version hooks

Voici ma classe d'origine:

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>
    )
  }
}

Ici se trouve le React hooks version:

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.log(visible) // visible is `true` when user clicks. It works
    setIsVisible(visible) // This does not set isVisible to `true`.
    console.log(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>
  )
}
5
Greg Forel

Tout comme setState, le comportement de mise à jour de l'état à l'aide de crochets nécessitera également un nouveau rendu et une mise à jour et, par conséquent, le changement ne sera pas immédiatement visible. Si toutefois vous essayez de consigner l'état en dehors de la méthode handleVisibleChange, vous verrez l'état de mise à jour

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

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

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

  console.log({ 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>
  )
}

Toute action que vous devez entreprendre en fonction de la mise à jour de l'état peut être effectuée à l'aide du crochet useEffect comme

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