在事件监听器中反应挂钩保存状态错误?

时间:2019-02-21 12:06:17

标签: javascript reactjs addeventlistener event-listener react-hooks

我有积分和一个更新积分的功能:

const [points, setPoints] = useState([])

const updatePoint = (updatedPoint) => {
  setPoints(points.map(point => (point.id === updatedPoint.id ? updatedPoint : point)))
}

我已将侦听器添加到标记:

window.google.maps.event.addListener(marker, 'dragend',
  function (markerLocal) {
    console.log(getPoints)       
  }
)

如果创建后单击第一个标记,它将在控制台中显示1点。 如果我创建并单击第二个,它会向我显示2分,因此它将状态保存在侦听器内部。但是,第二次保存后,第一个标记的点总和不变(被拖动时)。这是正确的行为吗?如何获得第一个标记的2分?每当我尝试更新点列表并单击第一个标记时,它只会给我一个点-这是错误的。

3 个答案:

答案 0 :(得分:1)

这可能是因为处理程序在声明时使用了points,在调用之前可能会对其进行更新。我对此类问题的解决方案是将其定义为参考:

const points = useRef([]);
// This means that instead of `setPoints` you will do points.current = newValue

const updatePoint = (updatePoint) => {
   points.current = points.current.map(...);
}

答案 1 :(得分:1)

尝试添加具有points依赖项的useEffect并为Google地图设置addEventListener。此处的问题是初始addEventListener所作用的范围。在常规JS中,您将始终在范围内拥有当前值,但是在挂钩中,您的代码将引用先前渲染中的陈旧值。就您而言,您引用的是将事件附加到Google Maps时points状态的值。我认为,这里最干净的解决方案是Leftium的解决方案,但您也可以出于“学术”目的尝试此解决方案:

const onGoogleMapsMarkerDragend = () => {
    console.log(points);
}
useEffect(() => {
    const dragendListener = window.google.maps.event.addListener(marker, 'dragend', onGoogleMapsMarkerDragend);
    return () => {
        window.google.maps.event.removeListener(dragendListener );
    }
}, [points];

不确定removeListener是否有效-请查阅文档

答案 2 :(得分:0)

如果使用以前的状态来计算新状态,例如您的示例,则应将旧状态的函数而不是新值直接传递给setPoints()

const updatePoint = (updatedPoint) => {
  setPoints((prevPoints) =>
      prevPoints.map(point => (point.id === updatedPoint.id ? updatedPoint : point)
  ))
}

Hooks API参考中的相关部分:Identity Server docs