Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React组件在重新渲染时创建状态的新实例,即使状态未更改_Javascript_Reactjs_Websocket_Socket.io - Fatal编程技术网

Javascript React组件在重新渲染时创建状态的新实例,即使状态未更改

Javascript React组件在重新渲染时创建状态的新实例,即使状态未更改,javascript,reactjs,websocket,socket.io,Javascript,Reactjs,Websocket,Socket.io,我将Socket.IO与React.js一起使用,我希望websocket仅在呈现特定组件时启动,因此我将websocket用作该组件的状态,如下所示: const Comp = () => { const {current: instance} = useRef({}); const ws = instance.ws = instance.ws || socketIO(); // ... the rest of the component ... }; const Comp

我将
Socket.IO
React.js
一起使用,我希望websocket仅在呈现特定组件时启动,因此我将websocket用作该组件的状态,如下所示:

const Comp = () => {
  const {current: instance} = useRef({});
  const ws = instance.ws = instance.ws || socketIO();
  // ... the rest of the component ...
};
const Comp=()=>{
const[ws]=useState(socketIO());
//…组件的其余部分。。。
};

但是当
Comp
重新呈现时,它会创建新的websocket连接,即使我没有对连接进行任何更改。过了一段时间,我得到了超过10个websocket连接。如何使组件仅保持1个连接?我不希望websocket连接成为全局连接。

记住,功能组件只是函数,所有关于函数的常见知识都适用。虽然钩子在幕后发挥了一些看似神奇的作用(这不是真正的神奇,只是它们有我们看不到的上下文信息),但组件函数中的代码按照通常的规则运行。这意味着这个代码

const Comp = () => {
  const [ws] = useState(socketIO());
  // ... the rest of the component ...
};
始终调用
socketIO
,以便它可以将其返回值传递到
useState

要仅计算一次值,当组件第一次创建时,请使用ref()表示非状态实例信息(这类信息将直接存储在类组件实例上),如下所示:

const Comp = () => {
  const {current: instance} = useRef({});
  const ws = instance.ws = instance.ws || socketIO();
  // ... the rest of the component ...
};
{}
仍然在每次调用
Comp
时进行计算,但这种开销很小。您从
useRef
中得到的是一个对象,该对象具有一个
current
属性,该属性引用一个可变对象,该对象在组件的整个生命周期内始终相同。第二行使用该对象的
ws
属性,如果它是falsy,则第一次初始化它

此用法在以下文件中列出:

但是,
useRef()
不仅适用于ref属性。它可以方便地保留任何可变值,类似于在类中使用实例字段的方式

下面是一个示例,其中有一个替代
socketIO

const{useRef,useState}=React;
函数socketIO(){
log(“socketIO调用”);
返回{};
}
常数Comp=()=>{
控制台日志(“被调用的组件”);
const{current:instance}=useRef({});
常量ws=instance.ws=instance.ws | | socketIO();
const[counter,setCounter]=useState(0);
返回(
{counter}setCounter(c=>c+1)}/>
);
};
render(,document.getElementById(“根”))


感谢您的详细回答。但是你能在这里给我解释一下链接分配吗:
const ws=instance.ws=instance.ws | | socketIO()
?@TríPhan-该表达式的工作原理如下:它计算
instance.ws | | socketIO()
,这意味着
|
运算符计算左手操作数(
instance.ws
),并且如果结果是真的(除
null
未定义的
0
NaN
,或
false
),它将该值作为其结果。如果左侧运算符的值为falsy(这些值中的任何一个),它将计算右侧(调用
socketIO
)并将该结果作为其结果。然后完成第一个赋值(
instance.ws=x
,其中
x
是第一个表达式的结果)。赋值的结果就是被赋值的值,所以表达式的结果也是
x
。然后完成
ws=x
部分。因此,第一次创建组件并运行
Comp
时,由于
instance
将是一个空白对象,
instance.ws
未定义
,并且
socketIO
将被调用;结果将分配给
instance.ws
ws
。下次调用
Comp
时,
instance.ws
将已经有一个truthy值,因此不会调用
socketIO
,而
ws
将获取该值。