如果该函数在挂钩之外调用

发布于 2025-01-17 12:38:32 字数 1662 浏览 0 评论 0原文

我有一个问题,我不知道如何解决。

基本上,我的想法是,我有一个只需要实例化一次的类(实例化是在 useMemo 中完成的,以便只完成一次),这个类实际上是一个调用处理程序的 websocket 实现(此处为 onCounterChanged)当它从后端接收到消息时),以便更新组件状态,但由于某种原因该处理程序保留旧的计数器状态值。这是代码:

class MyService {
  constructor(onCounterChange) {
    this.onCounterChange = onCounterChange;
  }
  start = () => {
//This setInterval is only used to try to reproduce the reality (an async event so for example 
//when a message is received from the server). So i call this onCounterChange every 2 sec to 
//simulate a message received from the server
    setInterval(() => {
      this.onCounterChange();
    }, 2000);
  };
}

const MyComponent = () => {
  const [counter, setCounter] = React.useState(0);
  const onCounterChanged = () => {
    console.log("onCounterChanged", counter);
    setCounter(counter + 1);
  };
//i'm using useMemo in order to keep the instance of MyService, because i'm doing some stuff
//(connect to the webSocket etc... in this class, i don't want to create an new instance on every 
//render and do the connection to the server again
  const myService = React.useMemo(() => new MyService(onCounterChanged), []);
  React.useEffect(() => {
    myService.start();
  }, []);
  return <div>{counter}</div>;
};

这是一个沙箱,可以查看发生了什么: https://codesandbox.io/s/blazing-tree -z1m99e?file=/src/App.js

您可以看到计数器没有递增,函数 onCounterChange 每秒都会调用一次,但计数器状态不会在该函数内部更新处理程序。我尝试使用 useCallback 修复它,但没有任何效果。

知道如何解决这个问题吗?我不是反应专家,所以如果我遗漏了什么,抱歉。

感谢您的阅读。

I have an issue and i don't know how to solve it.

Basically, the idea is that i have a class that i need to instanciate only once (instanciation is done in an useMemo in order to have it done only once), this class is in reality a websocket implementation which calls a handler (here onCounterChanged) when it receives a message from the backend), in order to update a component state, but for some reason this handler holds the old counter state value. Here is the code :

class MyService {
  constructor(onCounterChange) {
    this.onCounterChange = onCounterChange;
  }
  start = () => {
//This setInterval is only used to try to reproduce the reality (an async event so for example 
//when a message is received from the server). So i call this onCounterChange every 2 sec to 
//simulate a message received from the server
    setInterval(() => {
      this.onCounterChange();
    }, 2000);
  };
}

const MyComponent = () => {
  const [counter, setCounter] = React.useState(0);
  const onCounterChanged = () => {
    console.log("onCounterChanged", counter);
    setCounter(counter + 1);
  };
//i'm using useMemo in order to keep the instance of MyService, because i'm doing some stuff
//(connect to the webSocket etc... in this class, i don't want to create an new instance on every 
//render and do the connection to the server again
  const myService = React.useMemo(() => new MyService(onCounterChanged), []);
  React.useEffect(() => {
    myService.start();
  }, []);
  return <div>{counter}</div>;
};

Here is a sandbox to see what's happening :
https://codesandbox.io/s/blazing-tree-z1m99e?file=/src/App.js

You can see that the counter isn't incremented, the function onCounterChange is called every seconds but the counter state is not updated inside of that handler. I tried to fix it by using useCallback but nothing was working.

Any idea how can i fix this ? I'm not a pro of react so, sorry if i'm missing something.

Thanks for reading.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

神经暖 2025-01-24 12:38:32

您的更新状态存在问题,我做了一些重构。

当您尝试使用旧值更新状态时,您应该使用回调而不是传递“当前”值,避免传递当前状态值,因为它并不总是与实际状态值同步

const onCounterChanged = useCallback(() => {
    setCounter((currentValue) => {
      console.log({ currentValue });
      return currentValue + 1;
    });
  }, [setCounter]);

使用回调将确保您正在使用最新值

这是一个 CodeSandbox: https://codesandbox.io/s/goofy-sanderson-bfq3mh?file=/src/App.js

There is an issue with your update state, I did a little refactor.

When you try to update the state using the old value, you should use a callback instead of passing the "current" value, avoid passing the current state value because is not always in sync with the actual state value

const onCounterChanged = useCallback(() => {
    setCounter((currentValue) => {
      console.log({ currentValue });
      return currentValue + 1;
    });
  }, [setCounter]);

Using a callback will assure you that is using the latest value

Here is a CodeSandbox: https://codesandbox.io/s/goofy-sanderson-bfq3mh?file=/src/App.js

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文