【问题标题】:Unexpected behaviour of useState hookuseState 挂钩的意外行为
【发布时间】:2021-07-01 21:44:11
【问题描述】:

我在试用图像映射器库时发现了意外行为。处理函数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>
  );
}

【问题讨论】:

  • react-img-mapper 是 react-image-mapper 的克隆。你可能错过了。 react-image-mapper 没有维护,我解决了这个 react-img-mapper 的创建

标签: reactjs use-state


【解决方案1】:

ImageMapper is indeed memoizedDrew's approach 是正确的,是 calling the setState hook callback when the state update depends on its previous value 的推荐做法。

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

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

【讨论】:

  • 感谢您准确指出代码。您可能会建议任何文档来理解这种类型的记忆行为?
  • @RishabhSingh 好吧,我的答案中已经有一个关于functional updates 的链接,还有一个关于React.memo() 的链接,ImageMapper 用它来记忆它的道具。
  • 感谢您深入研究我的代码并找到一个非常好的替代方案
  • @NishargShah 感谢您使您的源代码易于阅读:) 非常有帮助
  • 欢迎您,您的称赞对我来说是一个巨大的加速。
【解决方案2】:

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

如果您使用功能状态更新,则单击突出显示的区域似乎可以按我认为的那样工作。功能状态更新通过从先前的状态与回调入队的渲染周期中的状态进行更新来工作。

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

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

演示

【讨论】:

  • 感谢您指出。虽然我知道功能状态更新会解决问题,但我并不完全知道为什么。您可能会建议任何文档来理解这种类型的记忆行为?
  • @RishabhSingh 我不知道任何临时文档,但大多从经验观察和经验中了解并认识到这个问题。计数器甚至是事实上的example React 用来解释功能状态更新,因为每次更新取决于前一个状态的值。
  • 我只是想进一步了解记忆化的工作原理。我故意让 count 变量只是为了让事情变得简单。似乎 ImageMapper 拍摄了 handleInc 的快照,以及当时为 0 的 count 变量的快照。稍后对于所有点击,它会继续使用该快照 0 而不是实际的计数状态变量。我说得对吗:- |
  • 您好@RishabhSingh,我是react-img-mapper 的所有者,是的,我记住了回调,这就是您获得初始值的原因,但正如@patrick 所说,您可以使用rerenderProps 或像我一样邮件里对你说可以使用之前的回调状态来更新你的状态,谢谢
  • @RishabhSingh 你对此非常敏感。简单来说,记忆化只是一种通过存储函数调用的结果来“加速”计算的方法,在这种情况下,它是该组件初始渲染周期中handleInc 的版本。您的按钮可以正常工作,因为它们每次渲染都会获得 handleInc 的新副本,但 Image-mapper 组件使用了缓存版本。
猜你喜欢
  • 2020-02-25
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
  • 2021-12-01
  • 1970-01-01
  • 2022-01-23
  • 2021-05-20
相关资源
最近更新 更多