0

我有一个关闭导航的按钮。此按钮跟随鼠标。一切正常,但我有一个 depricationwarning,我想摆脱它,但不知道具体如何。(我只知道useEffect起到了一定的作用:

这是课程:

import React from "react"

class NavigationCloseMouseButton extends React.Component {
  static defaultProps = {
    visible: true,
    offsetX: 0,
    offsetY: 0,
  }

  state = {
    xPosition: 0,
    yPosition: 0,
    mouseMoved: false,
    listenerActive: false,
  }

  componentDidMount() {
    this.addListener()
  }

  componentDidUpdate() {
    this.updateListener()
  }

  componentWillUnmount() {
    this.removeListener()
  }

  getTooltipPosition = ({ clientX: xPosition, clientY: yPosition }) => {
    this.setState({
      xPosition,
      yPosition,
      mouseMoved: true,
    })
  }

  addListener = () => {
    window.addEventListener("mousemove", this.getTooltipPosition)
    this.setState({ listenerActive: true })
  }

  removeListener = () => {
    window.removeEventListener("mousemove", this.getTooltipPosition)
    this.setState({ listenerActive: false })
  }

  updateListener = () => {
    if (!this.state.listenerActive && this.props.visible) {
      this.addListener()
    }

    if (this.state.listenerActive && !this.props.visible) {
      this.removeListener()
    }
  }

  render() {
    return (
      <div
        onClick={this.props.toggleNavigation}
        className="tooltip color-bg"
        style={{
          display:
            this.props.visible && this.state.mouseMoved ? "block" : "none",
          opacity: this.props.visible && this.state.mouseMoved ? "1" : "0",
          top: this.state.yPosition + this.props.offsetY,
          left: this.state.xPosition + this.props.offsetX,
        }}
      >
        Close Menu
      </div>
    )
  }
}

export default NavigationCloseMouseButton

这就是我到目前为止所做的,但结果有错误: ReferenceError: getTooltipPosition is not defined


import React, { useState, useEffect } from "react"

const NavigationCloseMouseButton = () => {
  const defaults = {
    visible: true,
    offsetX: 0,
    offsetY: 0,
  }

  const defaultState = {
    xPosition: 0,
    yPosition: 0,
    mouseMoved: false,
    listenerActive: false,
  }

  const [defaultProps, setDefaultProps] = useState(defaults)
  const [state, setState] = useState(defaultState)

  useEffect(() => {
    // Update the document title using the browser API
    addListener()
  }, [])

  getTooltipPosition = ({ clientX: xPosition, clientY: yPosition }) => {
    setState({
      xPosition,
      yPosition,
      mouseMoved: true,
    })
  }

  addListener = () => {
    window.addEventListener("mousemove", getTooltipPosition)
    setState({ listenerActive: true })
  }

  removeListener = () => {
    window.removeEventListener("mousemove", getTooltipPosition)
    setState({ listenerActive: false })
  }

  updateListener = () => {
    if (!state.listenerActive && props.visible) {
      addListener()
    }

    if (state.listenerActive && !props.visible) {
      removeListener()
    }
  }

  return (
    <div
      onClick={props.toggleNavigation}
      className="tooltip color-bg"
      style={{
        display: props.visible && state.mouseMoved ? "block" : "none",
        opacity: props.visible && state.mouseMoved ? "1" : "0",
        top: state.yPosition + props.offsetY,
        left: state.xPosition + props.offsetX,
      }}
    >
      Close Menu
    </div>
  )
}

export default NavigationCloseMouseButton

4

1 回答 1

0

设置默认值

您可以从 props 对象(函数组件的参数)中解构单个 props。在解构时,您可以使用=运算符设置未设置此道具时的默认值。

const NavigationCloseMouseButton = ({ visible = true, offsetX = 0, offsetY = 0, toggleNavigation }) => {

更新监听器

我相信有很多关于这个的很好的答案,所以我不会太详细。

您想要处理从useEffect. 您应该使用useEffect清理功能进行最终删除。我们不想添加和删除同一个监听器,所以我们可以用useCallback.

我不确定你要做什么listenerActive。这可能是一个道具,但它似乎也有点多余visible。我根本不知道我们需要这个。

计算偏移量

我也不知道传球offsetXoffsetY作为道具有意义。我们需要将鼠标放在工具提示的顶部才能使其可点击。我们可以测量div这个组件内部的工具提示并以这种方式处理它。

// ref to DOM node for measuring
const divRef = useRef<HTMLDivElement>(null);

// can caluculate offset instead of passing in props
const offsetX = -.5 * (divRef.current?.offsetWidth || 0);
const offsetY = -.5 * (divRef.current?.offsetHeight || 0);

动画

将 style 属性设置display"block""none"使任何类型的 CSS 转换变得困难。相反,我建议您通过更改className. 你仍然可以在这些类上设置display: blockdisplay: none,但我选择使用transform: scale(0);

代码

const NavigationCloseMouseButton = ({
  visible = true,
  toggleNavigation
}) => {

  // state of the movement
  const [state, setState] = useState({
    xPosition: 0,
    yPosition: 0,
    mouseMoved: false
  });

  // memoized event listener
  const getTooltipPosition = useCallback(
    // plain event, not a React synthetic event
    ({ clientX: xPosition, clientY: yPosition }) => {
      setState({
        xPosition,
        yPosition,
        mouseMoved: true
      });
    },
    []
  ); // never re-creates

  useEffect(() => {
    // don't need to listen when it's not visible
    if (visible) {
      window.addEventListener("mousemove", getTooltipPosition);
    } else {
      window.removeEventListener("mousemove", getTooltipPosition);
    }

    // clean-up function to remove on unmount
    return () => {
      window.removeEventListener("mousemove", getTooltipPosition);
    };
  }, [visible, getTooltipPosition]); // re-run the effect if prop `visible` changes

  // ref to DOM node for measuring
  const divRef = useRef(null);

  // can caluculate offset instead of passing in props
  const offsetX = -.5 * (divRef.current?.offsetWidth || 0);
  const offsetY = -.5 * (divRef.current?.offsetHeight || 0);

  // don't show until after mouse is moved
  const isVisible = visible && state.mouseMoved;

  return (
    <div
      ref={divRef}
      onClick={toggleNavigation}
      // control most styling through className
      className={`tooltip ${isVisible ? "tooltip-visible" : "tooltip-hidden"}`}
      style={{
        // need absolute position to use top and left
        position: "absolute",
        top: state.yPosition + offsetY,
        left: state.xPosition + offsetX
      }}
    >
      Close Menu
    </div>
  );
};

其他用途

通过删除一些硬编码的细节,我们可以轻松地使其变得NavigationCloseMouseButton更加灵活。MovingTooltip

  • props.children从而不是总是使用“关闭菜单”获取内容
  • 接受 aclassName作为道具
  • 将名称更改toggleNavigationonClick

代码沙盒演示

于 2021-03-05T22:39:19.357 回答