最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React hook saved state in Event Listener wrong? - Stack Overflow

programmeradmin1浏览0评论

I have points and a function to update points:

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

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

I've added a Listener to the marker:

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

If I click on first marker after I've created it, it shows me 1 point in the console. If I create and click second it shows me 2 points, So it saves the state inside of the listener. However, after the second save, the sum of points for the first marker doesn't change(when it gets dragged). Is this the right behaviour? How can I get two points for the first marker? Whenever I try to update my point list and click the 1st marker, it gives me only one point - that's wrong.

I have points and a function to update points:

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

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

I've added a Listener to the marker:

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

If I click on first marker after I've created it, it shows me 1 point in the console. If I create and click second it shows me 2 points, So it saves the state inside of the listener. However, after the second save, the sum of points for the first marker doesn't change(when it gets dragged). Is this the right behaviour? How can I get two points for the first marker? Whenever I try to update my point list and click the 1st marker, it gives me only one point - that's wrong.

Share Improve this question edited Feb 21, 2019 at 12:17 Clydeston 271 silver badge9 bronze badges asked Feb 21, 2019 at 12:06 Pashuk xCodePashuk xCode 811 silver badge8 bronze badges 1
  • I think you may need to show more of your code - what is getPoints? Where are you setting up your listeners? – Joe Clay Commented Feb 21, 2019 at 12:44
Add a ment  | 

3 Answers 3

Reset to default 7

Try adding useEffect with points dependency and set addEventListener for google maps. An issue here is the scope that the initial addEventListener is working on. In regular JS you would always have the current value in the scope, however, in hooks, your code will reference stale values from previous renders. In your case, you are referencing the values your points state was at the time of attaching the event to Google Maps. The cleanest solution here, in my opinion, is the Leftium's one, but you can also try this one for 'academic' purposes:

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

Not sure if removeListener is valid - check with the documentation

This is probably because the handler uses the points at the time of declaration, which might be updated before it is invoked. My solution to such issues was to define it as a ref:

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

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

If a previous state is used to calculate the new state, as in your example, you should pass setPoints() a function of the old state instead of the new value directly:

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

Relevant section from Hooks API Reference: Functional updates for useState

发布评论

评论列表(0)

  1. 暂无评论