useState 挂钩的意外行为

Unexpected behaviour of useState hook

我在试用图像映射器库时发现了意外行为。处理函数 handleInc 的行为不同,具体取决于它是由 + 按钮触发还是通过单击图像中的突出显示区域触发(需要四处移动鼠标才能显示突出显示区域)。

当使用 + 按钮时,行为符合预期,但当单击图像中的突出显示区域时,状态变量 count 似乎并没有超出 1

相同函数背后的原因是什么 handleInc 表现不同。

这是代码(sandbox下面的代码)

import { useState } from "react";
import "./styles.css";
// https://github.com/img-mapper/react-img-mapper
import ImageMapper from "react-img-mapper";

const URL =
  "https://helpx.adobe.com/content/dam/help/en/stock/how-to/visual-reverse-image-search/jcr_content/main-pars/image/visual-reverse-image-search-v2_intro.jpg";

export default function App() {
  const [count, setCount] = useState(0);
  const handleInc = () => {
    // this print expected value when + button is clicked
    // but print 0 if highlighted area is clicked
    console.log(count);
    setCount(count + 1);
  };
  const handleDec = () => {
    console.log(count);
    setCount(count - 1);
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={handleInc}>+</button>
      {count}
      <button onClick={handleDec}>-</button>

      <ImageMapper
        src={URL}
        map={{
          name: "asdf",
          areas: [
            {
              id: 0,
              active: true,
              title: "BB(1-4)",
              shape: "poly",
              name: "BB(1-4)",
              fillColor: "#eab54d4d",
              strokeColor: "black",
              coords: [
                260,
                142,
                77,
                196,
                184,
                530,
                840,
                529,
                928,
                283,
                894,
                26,
                389,
                53,
                343,
                31,
                321,
                90
              ]
            }
          ]
        }}
        stayMultiHighlighted
        onClick={handleInc}
      />
    </div>
  );
}

似乎 ImageMapper 组件正在记忆回调,换句话说,它已经关闭了初始 count 状态值并且从那时起不再更新。

如果您使用功能状态更新,那么单击突出显示的区域似乎会像我认为的那样起作用。功能状态更新通过从先前状态更新到回调排队的渲染周期中的状态来工作。

const handleInc = () => {
  setCount(count => count + 1);
};

const handleDec = () => {
  setCount(count => count - 1);
};

演示

ImageMapper is indeed memoized. is correct and the recommended practice for calling the setState hook callback when the state update depends on its previous value.

或者,ImageMapper 组件的界面有一个 rerenderProps 属性,您可以指定将 onClick 添加到其敏感列表并覆盖记忆:

<ImageMapper
  ...
  onClick={handleInc}
  rendererProps={['onClick']}
/>