Reactjs 如何访问eventHandler中的React状态?

Reactjs 如何访问eventHandler中的React状态?,reactjs,leaflet,react-hooks,react-leaflet,use-state,Reactjs,Leaflet,React Hooks,React Leaflet,Use State,这是我的状态: const [markers, setMarkers] = useState([]) 我在useEffect挂钩中初始化了一张传单地图。它有一个点击事件处理程序 useEffect(() => { map.current = Leaflet.map('mapid').setView([46.378333, 13.836667], 12) . . . map.current.on('click', onMapClick) }, []

这是我的状态:

const [markers, setMarkers] = useState([])
我在useEffect挂钩中初始化了一张传单地图。它有一个
点击
事件处理程序

useEffect(() => {
    map.current = Leaflet.map('mapid').setView([46.378333, 13.836667], 12)
    .
    .
    .
    map.current.on('click', onMapClick)
}, []
在该
onmaplick
中,我在地图上创建了一个标记,并将其添加到状态:

const onMapClick = useCallback((event) => {
    console.log('onMapClick markers', markers)
    const marker = Leaflet.marker(event.latlng, {
        draggable: true,
        icon: Leaflet.divIcon({
            html: markers.length + 1,
            className: 'marker-text',
        }),
    }).addTo(map.current).on('move', onMarkerMove)

    setMarkers((existingMarkers) => [ ...existingMarkers, marker])
}, [markers, onMarkerMove])
但我也想访问这里的
标记
状态。但我看不懂这里的标记。它总是初始状态。我试图通过按钮的onClick处理程序调用
onmaclick
。在那里我可以阅读
标记
。如果原始事件从地图开始,为什么我不能读取标记?如何读取onmaclick中的状态变量

以下是一个例子:
当您在地图中单击并查看控制台时,您会看到
onmaclick
中的
markers
数组保持为空,而在侦听
markers

React状态的
useffect
中填充该数组时,它是异步的,并且不会立即保证为您提供新状态,至于你的问题如果原始事件从映射开始,我为什么不能读取标记呢这是一种异步性质,函数基于当前闭包和状态更新使用状态值这一事实将反映在下一次重新渲染中,现有闭包不受影响,但会创建新的闭包,您不会在类组件上遇到这个问题,因为类组件中有这个具有全局范围的实例

作为开发组件的人员,我们应该确保从调用组件的位置控制组件,而不是处理状态的函数闭包,每次状态更改时,它都会重新呈现。您的解决方案是可行的,您应该在函数需要时将值传递给函数,无论传递什么事件或操作

编辑:-很简单,只需将params或deps传递给useffect,并将回调封装在其中,对于您的情况,它将是

useEffect(() => {
    map.current = Leaflet.map('mapid').setView([46.378333, 13.836667], 12)
    .
    .
    .
    map.current.on('click',()=> onMapClick(markers)) //pass latest change
}, [markers] // when your state changes it will call this again

欲了解更多信息,请查看这一个,它将帮助您长期

很长,但你会明白为什么会发生这种情况以及更好的修复方法。闭包尤其是一个问题(也很难理解),主要是当我们设置依赖于状态的单击处理程序时,如果具有新作用域的处理程序函数未重新附加到单击事件,则闭包保持未更新状态,因此陈旧状态保持在单击处理程序函数中

如果您在组件中完全理解它,
useCallback
将返回对更新函数的新引用,即
onmaplick
在其范围内具有更新的标记(状态),但由于您仅在安装组件时才在开始时设置“click”处理程序,单击处理程序保持未更新状态,因为您在(!map.current)
中设置了一个复选框
,该复选框将阻止在映射上附加任何新的处理程序

// in sandbox map.js line 40
  useEffect(() => {
    // this is the issue, only true when component is initialized
    if (! map.current) {
      map.current = Leaflet.map("mapid4").setView([46.378333, 13.836667], 12);
      Leaflet.tileLayer({ ....}).addTo(map.current);
      // we must update this since onMapClick was updated
      // but you're preventing this from happening using the if statement
      map.current.on("click", onMapClick);
    }

  }, [onMapClick]);
现在我尝试移动
map.current.on(“单击”,onmaclick)退出
if
块,但有一个问题,我们没有用新函数替换click处理程序,而是使用它(基本上是堆叠事件处理程序),因此我们必须在添加新的处理程序之前删除旧的处理程序,否则每次更新
onmaclick
时都会添加多个处理程序。对于它,我们有
off()
函数

这是更新后的代码

// in sandbox map.js line 40
useEffect(() => {
  // this is the issue, only true when component is initialized
  if (!map.current) {
    map.current = Leaflet.map("mapid4").setView([46.378333, 13.836667], 12);
    Leaflet.tileLayer({ ....
    }).addTo(map.current);
  }

  // remove out of the condition block
  // remove any stale click handlers and add the updated onMapClick handler
  map.current.off('click').on("click", onMapClick);

}, [onMapClick]);
这是一个链接,指向更新后的,运行良好的

现在有另一个解决方法,不必每次都替换单击处理程序。i、 e一些全球性的,我相信这并不太糟糕

为此,将
globalMarkers
添加到组件外部但在组件上方,并每次更新它

let updatedMarkers = [];

const Map4 = () => {
  let map = useRef(null);
  let path = useRef({});
  updatedMarkers =  markers; // update this variable each and every time with the new markers value
  ......

  const onMapClick = useCallback((event) => {
   console.log('onMapClick markers', markers)
   const marker = Leaflet.marker(event.latlng, {
      draggable: true,
      icon: Leaflet.divIcon({
        // use updatedMarkers here
        html: updatedMarkers.length + 1,
        className: 'marker-text',
      }),
    }).addTo(map.current).on('move', onMarkerMove)

    setMarkers((existingMarkers) => [ ...existingMarkers, marker])
  }, [markers, onMarkerMove])
 .....

} // component end
这个也很好用,用这个代码链接到。这个工作得更快


最后,上述将其作为参数传递的解决方案也可以!我更喜欢更新了
if
块的那一个,因为它很容易修改,而且你可以得到它背后的逻辑。

谢谢你的回答。我知道React状态是异步的,但我不知道如何重构我的解决方案,以便映射事件调用的eventHandler可以访问该状态。