我对此的react 是新的.我正在try 将一个用VanillaJS编写的外部库集成到我的Reaction应用程序中.外部库在其代码的一部分中设置window.addEventListener(),并异步地对某个对象进行更新/改变.

如果我将state对象从我的Reaction应用程序传递给这个外部方法,我可以观察到当某个相关事件发生时,状态对象会发生变化.例如,如果我等待几毫秒,然后将状态打印到Reaction应用程序的控制台上,我就可以看到这一点.现在,状态不同了,但组件似乎没有重新渲染.

const myObj = { "counter": 0 }
const [state, SetState] = useState(myObj);

useEffect(() => {
    // console.log(state); -> { "counter": 0 }
    externalLibraryEventListener(state); // externalLibraryEventListener increments myObj["counter"] by 1 asynchronously. 
    // setTimeout(() => {console.log(state)}, 2000) -> { "counter": 1 }
    }
), [state];

在我的研究中,到目前为止,我已经读到过关于对数据的浅层和深层副本进行不同解释以及不同react 的react .我不确定这是不是正在发生的事情,但也许这是正确的道路.我的另一个预感是,它不会重新呈现组件,因为没有任何前端更改(如鼠标单击或表单填充)来更改状态;从Reaction应用程序的Angular 来看,状态对象似乎正在内存中更改.

最后,我希望将一些对象从我的Reaction应用程序传递给VanillaJS代码,监听状态的变化,然后在有这种变化的情况下让我的Reaction应用程序响应.也许这是不可能的react ,在try 了许多小时后,我想我应该在这里问一下.在提出解决方案时,在我的情况下,最好是在不更改VanillaJS代码的情况下处理来自Reaction应用程序端的一切.

推荐答案

在Reaction中,只有一种方法可以引发重现:您必须调用setState.此外,您传递给setState的值必须是一个新值(由Object.is判断标识,类似于===).因此,如果状态是对象,则需要将其设置为新对象,而不是改变旧对象.

理想情况下,这个外部库可以通过某种方式告诉您它何时进行了更改,然后您可以对其执行操作以调用setState.类似于以下内容(我正在发明外部库代码):

const [counter, setCounter] = useState(0);
useEffect(() => {
  const unsubscribe = externalLibrary.onChange((newValue) => {
    setCounter(newValue);
  });
  return unsubscribe
}, []);

如果图书馆没有办法告诉你什么时候发生了变化,你就得有创意了.如果库正在写入对象的属性,也许您可以使用setter函数创建一个对象,并将其用作通知的一种方式.

const [counter, setCounter] = useState(0);
useEffect(() => {
  const interceptor = {
    _counter: 0;
    get counter() {
      return this._counter;
    },
    set counter(newValue) {
      this._counter = newValue;
      setCounter(newValue);
    }
  }
  externalLibraryEventListener(interceptor);
}, []);

您的代码有一个带有setTimeout的注释位.这也可能是一种 Select :轮询更改,然后设置状态.我不认为这是最好的解决方案,因为它会在您注意到更改之前引入延迟,并且您会遇到这样的情况:您确实在判断更改,但什么都没有发生.

const [counter, setCounter] = useState(0);
useEffect(() => {
  const myObj = { counter: 0 }
  externalLibraryEventListener(myObj);

  let prevValue = 0;
  const id = setInterval(() => {
     if (myObj.counter !== prevValue) {
       setCounter(myObj.counter);
       prevValue = myObject.counter;
     }
  }, 500);

  return () => clearInterval(id);
}, []);

在我的示例中,我故意将状态更改为数字而不是对象.如果出于某种原因需要将其作为对象保留,请记住,每次设置状态时都必须创建一个新对象.变异相同的对象将看起来好像什么都没有改变.因此,如果您需要使用该对象设置状态,请确保首先复制它

setState({ ...stateWhichWasMutated });

Javascript相关问答推荐

网页自检测外部元素无法加载

Redux查询多个数据库Api reducerPath&

浮动Div的淡出模糊效果

为什么promise对js中的错误有一个奇怪的优先级?

如何从html元素创建树 struct ?

编剧如何获得一个div内的所有链接,然后判断每个链接是否都会得到200?

在HTML语言中调用外部JavaScript文件中的函数

在使用位板时,如何在Java脚本中判断Connect 4板中中柱的对称性?

面对代码中的错误作为前端与后端的集成

一个实体一刀VS每个实体多刀S

当标题被点击时,如何使内容出现在另一个div上?

构建器模式与参数对象输入

如何在脚本编译后直接将RxJ模块导入浏览器(无需Angel、webpack、LiteServer)

如何在下一个js中更改每个标记APEXCHARTS图表的 colored颜色

FindByIdAndUpdate在嵌套对象中创建_id

用Reaction-RT-Chart创建实时条形图

调用特定数组索引时,为什么类型脚本不判断未定义

从异步操作返回对象

如何调整下拉内容,使其不与其他元素重叠?

JS/css:将数字输入的S函数和可调整大小的元素S函数绑定在一起