【问题标题】:React useCallback does not get updated on state changeReact useCallback 不会在状态更改时更新
【发布时间】:2019-08-22 18:24:01
【问题描述】:

下面的示例是一个简化的摘录,其中子组件根据鼠标行为发出事件。 React 然后应该根据发出的事件更新 DOM。

function SimpleSample() {
  const [addons, setAddons] = React.useState<any>({
    google: new GoogleMapsTile('google'),
  })
  const [tooltip, setTooltip] = React.useState<null | { text: string[]; x; y }>(null)
  React.useEffect(() => {
    // ...
  }, [])
  const mapEventHandle = React.useCallback(
    (event: MapEvents) => {
      console.log('event', event.type, tooltip) // LOG 1
      if (event.type === MapEventType.mouseoverPopup_show) {
        setTooltip({ text: event.text, x: event.coordinates[0], y: event.coordinates[1] })
      } else if (event.type === MapEventType.mouseoverPopup_move) {
        if (tooltip) setTooltip({ ...tooltip, x: event.coordinates[0], y: event.coordinates[1] })
      } else if (event.type === MapEventType.mouseoverPopup_hide) {
        setTooltip(null)
      }
    },
    [tooltip]
  )
  console.log('render', tooltip) // LOG 2

  return <MapComponent addons={addons} onEvent={mapEventHandle} />
}

预期的事件顺序如下:

  1. 发出mouseoverPopup_show,然后tooltip从null变为值,发生重新渲染
  2. mouseoverPopup_move 被发射,然后tooltip 被更新,触发重新渲染

实际发生了什么:

  • Lo​​gpoint LOG 2 记录tooltip 的更新值(正确)
  • 当再次调用mapEventHandle 时,该闭包内的tooltip 的值(日志点LOG 1)永远不会更新,始终为null

我错过了什么吗?用错了钩子?

这是一个代码框

https://codesandbox.io/s/blissful-torvalds-wm27f

编辑:解码箱示例 setTooltip 甚至没有触发重新渲染

【问题讨论】:

  • 这是有效的:codesandbox.io/s/inspiring-gauss-bnvdc。我刚刚从代码中删除了event.coordinates,因为它不会在您的示例中定义(这些事件不是实际的鼠标事件)。
  • 哦,只是查看codeandbox的控制台而不是浏览器控制台就被骗了,是的,它正在工作......好吧,这个错误是在创建示例时引入的。我要仔细看看源...

标签: reactjs typescript react-hooks


【解决方案1】:

感谢大家的帮助,问题似乎在 &lt;MapComponent/&gt; 的依赖项中。它最终保存了对旧回调的引用。仍然需要注意,我可能不会面对类组件......

//something like this
class MapComponent {
   emitter = this.props.onChange //BAD
   emitter = (...i) => this.props.onChange(...i) //mmkay
}

【讨论】:

    【解决方案2】:

    我认为event.coordinates 未定义,因此event.coordinates[0] 会导致错误。

    如果您这样做:setTooltip({working:'fine'}); 您会收到类型错误,但它确实会设置工具提示状态并重新呈现。

    【讨论】:

    • 是的,我在调整代码以适应问题时失败了......仔细查看源代码,以后可能会编辑它,ty
    【解决方案3】:

    感谢您的回答,它帮助我调试了我的,这有点不同。我的不工作,因为回调引用保存在子组件的状态值中。

    const onElementAdd = useCallBack(...)..
    <Dropzone onElementAdded={props.onElementAdded} />
    
    export const Dropzone = (props: DropzoneProps): JSX.Element => {
        const [{ isOver }, drop] = useDrop(
            () => ({
            accept: props.acceptedTypes,
            drop: (item: BuilderWidget, monitor): void => {
                if (monitor.didDrop()) return;
                props.onElementAdded(item);
            },
        }),
        // missed props.onElementAdded here
        [props.onElementAdded, props.acceptedTypes, props.disabled],
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 2020-07-18
      • 2019-04-10
      • 2020-06-25
      • 2020-05-08
      • 2018-11-29
      • 1970-01-01
      相关资源
      最近更新 更多