React Hooks - 修改后的状态不会立即反映

IT技术 reactjs typescript react-hooks
2021-04-15 07:16:24

我正在尝试使用React钩子将类重构为无状态组件

组件本身非常简单,我看不出我哪里出错了,因为它几乎是从 react 文档复制粘贴的。

当用户单击按钮时,组件会显示一个弹出窗口(按钮通过props传递给我的组件)。我正在使用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.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>
  )
}
1个回答

与 setState 非常相似,使用钩子的状态更新行为也需要重新渲染和更新,因此更改不会立即可见。但是,如果您尝试在 handleVisibleChange 方法之外记录状态,您将看到更新状态

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

您需要根据状态是否更新而采取的任何操作都可以使用useEffect钩子来完成,例如

useEffect(() => {
   // take action when isVisible Changed
}, [isVisible])
@ShubhamKhatri 这是否意味着更改处理程序也应该移动到useEffect 钩子
2021-06-14 07:16:24
我也面临类似的问题,但没有找到解决方案。
2021-06-15 07:16:24
谢谢 Shubham,我现在可以看到值更新了。但是,由于在重新渲染时isVisible变为true,我不明白为什么弹出窗口没有出现。我阅读了有关 useEffect 的文档,但我不明白为什么我需要使用它来显示弹出窗口,因为isVisible确实更改为true?
2021-06-17 07:16:24
你不需要使用useEffect。那只是额外的信息
2021-06-20 07:16:24