从回调中访问状态

IT技术 reactjs typescript
2022-07-20 02:04:37

我无法从回调中访问组件状态。

状态值num正确更改,但此类更改对加载时定义的回调函数不可见。

import React, {useState} from "react";

class MyObject {
  callback: (() => void);

  constructor(callback: () => void) {
    this.callback = callback;
  }
};

export const TestPage = () => {
  const [num, setNum] = useState<number>(0);

  // will print the changing values
  console.log(`num: ${num}`);

  const counter = useState<MyObject>(() => new MyObject(() => {
    // will always print 0
    console.log(`from callback. num: ${num}`);
  }))[0];

  const btnClick = () => {
    setNum((new Date()).getTime());
    counter.callback();
  };

  return (
      <div>Test, num: {num}
        <div>
          <button onClick={btnClick}>click to update state</button>
        </div>
      </div>
  );
}

普通的非 React 代码不会发生上述情况,如下所示

  let myVar = 0;
  const obj = new MyObject(() => console.log(`myVar: ${myVar}`));
  obj.callback(); // prints 0
  myVar = 1;
  obj.callback(); // prints 1

编辑:我试图重现闭包的问题,​​但我不能

 const makeFun = (callback: (() => void)) => {
    return () => {
      callback();
    }
  }
  let myVar = 0;
  const f1 = makeFun(() => console.log(`myVar: ${myVar}`));
  myVar = 1;
  const f2 = makeFun(() => console.log(`myVar: ${myVar}`));
  f1(); // prints 1
  f2(); // prints 1

所以我怀疑是特定于 React 和 useState 的。

有任何想法吗?

编辑#2:解决方案。这是如何使它在非 React 代码中可见。

let callbackPersistent: (() => void);
const createCallback = (callback: (() => void)) => {
  if (!callbackPersistent) {
    callbackPersistent = callback;
  }
  return callbackPersistent;
}

const myFunction = (num:number) => {
  const callback = createCallback(() => console.log(`callback num: ${num}`));
  callback();
};

然后将其称为

  myFunction(0); // prints 0
  myFunction(1); // prints 0

只有一个回调实例,它指向它第一次创建时看到的值。

编辑#3

useRef使用and可以找到一个合理的解决方案useEffect,如下所示:

import React, {useEffect, useRef, useState} from "react";

class MyObject {
  callback: (() => void);

  constructor(callback: () => void) {
    this.callback = callback;
  }
};

export const TestPage = () => {
  const [num, setNum] = useState<number>(0);
  const numRef = useRef(num);

  // will print the changing values
  console.log(`num: ${num}`);

  const counter = useState<MyObject>(() => new MyObject(() => {
    // will always print the latest value
    console.log(`from callback. num: ${numRef.current}`);
  }))[0];

  useEffect(()=> {numRef.current = num}, [num]);

  const btnClick = () => {
    setNum(new Date().getTime());
    counter.callback();
  };

  return (
      <div>Test, num: {num}
        <div>
          <button onClick={btnClick}>click to update state</button>
        </div>
      </div>
  );
}

useRef保证numRef在多次调用中始终是同一个对象。当值num更改时,onEffect调用将更新numRef.current值,然后由回调访问。只有一个回调实例和numRef存在,确保正确拾取更改

0个回答
没有发现任何回复~