React 在事件上重复渲染
React renders repeatedly on event
我在我的网站上使用套接字,并且有一个事件,其中一个用户可以向服务器发送一个词,服务器向每个人发出(art-addpic
)一个与该词相对应的图像 URL ,但只有具有 isArtist=true
的用户才能响应该事件。
艺术家的页面应该使用收到的 URL 更新现有图像列表 URLs (optionImages
)。但是当接收到事件时,列表中的所有图像都被接收到的 URL 替换。此外,呈现图像列表 ArtBoard
的组件不会使用更新后的 URL 重新呈现。
我是 React 的新手。我哪里错了?
我已经检查过服务器,事件 art-addpic
只广播了一次。
Arena.js:(发生这种情况的网页):
import React, { useEffect, useState } from "react";
import Leaderboard from "../comps/Leaderboard";
import { io } from "socket.io-client";
import Service from "../Service";
import DetBoard from "../comps/DetBoard";
import ArtBoard from "../comps/ArtBoard";
const username = "Nick"
const roomkey="abc"
let userid;
if(localStorage.getItem('userid')){
userid = localStorage.getItem('userid')
}
else{
userid = Service.makeid(5);
localStorage.setItem('userid', userid);
}
function useForceUpdate(){
const [value, setValue] = useState(0); // integer state
return () => setValue(value => value + 1); // update the state to force render
}
// const [userid,setUserId] =
const socket = io('http://localhost:3001', {query:"username="+username+"&roomkey="+roomkey+"&userid="+userid});
const Arena = (props)=>{
const [isArtist, setIsArtist] = useState(false);
const [focusImage, setFocusImage] = useState('https://i.imgur.com/61HsZCU.jpeg')
const [players, setPlayers] = useState([]);
const [optionImages, setOptionImages] = useState([
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg'
])
useEffect(()=>{
socket.on('connect',()=>{
console.log("connected")
})
socket.on('players', (data)=>{
data = JSON.parse(data)
console.log(data)
setPlayers(data)
})
socket.on('artist', (data)=>{
if(data===userid){
console.log('You are an artist, Mr White.')
setIsArtist(true);
}
else{
setIsArtist(false);
}
})
socket.on('art-addpic', (data)=>{
data = JSON.parse(data)
console.log(data)
let tempOps =optionImages;
tempOps.splice(0, 1);
tempOps.push(data.url)
console.log(tempOps)
setOptionImages(tempOps);
})
}, [
optionImages
]);
if(isArtist){
return(
<div>
<Leaderboard players={players}></Leaderboard>
{/* <ArtBoard></ArtBoard> */}
<ArtBoard socket={socket} focusImage={focusImage} optionImages={optionImages} setOptionImages={setOptionImages}/>
</div>
);
}
else{
return (
<div>
<Leaderboard players={players}></Leaderboard>
{/* <ArtBoard></ArtBoard> */}
<DetBoard socket={socket} focusImage={focusImage}/>
</div>
);
}
}
export default Arena;
你至少有几个问题:
useEffect
挂钩没有返回清理函数来取消订阅套接字连接,因此它们保持打开状态。
optionImages
状态突变。
- 更新
optionImages
状态会重新触发 useEffect
回调,从而创建更多订阅。
挂钩代码
useEffect(() => {
socket.on('connect', () => {
console.log("connected");
});
socket.on('players', (data) => {
data = JSON.parse(data);
console.log(data);
setPlayers(data);
});
socket.on('artist', (data) => {
if (data === userid) {
console.log('You are an artist, Mr White.');
setIsArtist(true);
} else {
setIsArtist(false);
}
});
socket.on('art-addpic', (data) => {
data = JSON.parse(data);
console.log(data);
let tempOps = optionImages; // (2) tempOps is reference to optionImages state
tempOps.splice(0, 1); // (2) mutation!
tempOps.push(data.url); // (2) mutation!
console.log(tempOps);
setOptionImages(tempOps); // (2,3) saved state reference back into state
});
// (1) missing cleanup function
}, [optionImages]); // (3) state updated in hook
据我所知,主要问题出在 'art-addpic'
事件上。似乎您想从 optionImages
状态中删除第一个元素并在末尾添加一个新的 URL。
如果是这样的话我有以下建议:
- Return 取消订阅套接字连接的清理函数。
- 删除所有
useEffect
钩子依赖项,以便在组件安装时钩子 运行 一次以建立套接字订阅,并在卸载时清除它们。
- 使用
optionImages
的功能状态更新来删除作为外部依赖项的状态。
挂钩代码
useEffect(() => {
socket.on('connect', () => {
console.log("connected");
});
socket.on('players', (data) => {
const parsedData = JSON.parse(data);
console.log(parsedData);
setPlayers(parsedData);
});
socket.on('artist', (data) => {
setIsArtist(data === userid);
});
socket.on('art-addpic', (data) => {
const parsedData = JSON.parse(data);
console.log(parsedData);
setOptionImages(optionImages =>
// Shallow copy into array, append URL, slice & keep last 4 elements
[...optionImages, parsedData.url].slice(-4),
);
});
return () => {
socket.removeAllListeners();
}
}, []);
useEffect(() => {
if (isArtist) {
console.log('You are an artist, Mr White.');
}
}, [isArtist]);
我在我的网站上使用套接字,并且有一个事件,其中一个用户可以向服务器发送一个词,服务器向每个人发出(art-addpic
)一个与该词相对应的图像 URL ,但只有具有 isArtist=true
的用户才能响应该事件。
艺术家的页面应该使用收到的 URL 更新现有图像列表 URLs (optionImages
)。但是当接收到事件时,列表中的所有图像都被接收到的 URL 替换。此外,呈现图像列表 ArtBoard
的组件不会使用更新后的 URL 重新呈现。
我是 React 的新手。我哪里错了?
我已经检查过服务器,事件 art-addpic
只广播了一次。
Arena.js:(发生这种情况的网页):
import React, { useEffect, useState } from "react";
import Leaderboard from "../comps/Leaderboard";
import { io } from "socket.io-client";
import Service from "../Service";
import DetBoard from "../comps/DetBoard";
import ArtBoard from "../comps/ArtBoard";
const username = "Nick"
const roomkey="abc"
let userid;
if(localStorage.getItem('userid')){
userid = localStorage.getItem('userid')
}
else{
userid = Service.makeid(5);
localStorage.setItem('userid', userid);
}
function useForceUpdate(){
const [value, setValue] = useState(0); // integer state
return () => setValue(value => value + 1); // update the state to force render
}
// const [userid,setUserId] =
const socket = io('http://localhost:3001', {query:"username="+username+"&roomkey="+roomkey+"&userid="+userid});
const Arena = (props)=>{
const [isArtist, setIsArtist] = useState(false);
const [focusImage, setFocusImage] = useState('https://i.imgur.com/61HsZCU.jpeg')
const [players, setPlayers] = useState([]);
const [optionImages, setOptionImages] = useState([
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg',
'https://i.imgur.com/61HsZCU.jpeg'
])
useEffect(()=>{
socket.on('connect',()=>{
console.log("connected")
})
socket.on('players', (data)=>{
data = JSON.parse(data)
console.log(data)
setPlayers(data)
})
socket.on('artist', (data)=>{
if(data===userid){
console.log('You are an artist, Mr White.')
setIsArtist(true);
}
else{
setIsArtist(false);
}
})
socket.on('art-addpic', (data)=>{
data = JSON.parse(data)
console.log(data)
let tempOps =optionImages;
tempOps.splice(0, 1);
tempOps.push(data.url)
console.log(tempOps)
setOptionImages(tempOps);
})
}, [
optionImages
]);
if(isArtist){
return(
<div>
<Leaderboard players={players}></Leaderboard>
{/* <ArtBoard></ArtBoard> */}
<ArtBoard socket={socket} focusImage={focusImage} optionImages={optionImages} setOptionImages={setOptionImages}/>
</div>
);
}
else{
return (
<div>
<Leaderboard players={players}></Leaderboard>
{/* <ArtBoard></ArtBoard> */}
<DetBoard socket={socket} focusImage={focusImage}/>
</div>
);
}
}
export default Arena;
你至少有几个问题:
useEffect
挂钩没有返回清理函数来取消订阅套接字连接,因此它们保持打开状态。optionImages
状态突变。- 更新
optionImages
状态会重新触发useEffect
回调,从而创建更多订阅。
挂钩代码
useEffect(() => {
socket.on('connect', () => {
console.log("connected");
});
socket.on('players', (data) => {
data = JSON.parse(data);
console.log(data);
setPlayers(data);
});
socket.on('artist', (data) => {
if (data === userid) {
console.log('You are an artist, Mr White.');
setIsArtist(true);
} else {
setIsArtist(false);
}
});
socket.on('art-addpic', (data) => {
data = JSON.parse(data);
console.log(data);
let tempOps = optionImages; // (2) tempOps is reference to optionImages state
tempOps.splice(0, 1); // (2) mutation!
tempOps.push(data.url); // (2) mutation!
console.log(tempOps);
setOptionImages(tempOps); // (2,3) saved state reference back into state
});
// (1) missing cleanup function
}, [optionImages]); // (3) state updated in hook
据我所知,主要问题出在 'art-addpic'
事件上。似乎您想从 optionImages
状态中删除第一个元素并在末尾添加一个新的 URL。
如果是这样的话我有以下建议:
- Return 取消订阅套接字连接的清理函数。
- 删除所有
useEffect
钩子依赖项,以便在组件安装时钩子 运行 一次以建立套接字订阅,并在卸载时清除它们。 - 使用
optionImages
的功能状态更新来删除作为外部依赖项的状态。
挂钩代码
useEffect(() => {
socket.on('connect', () => {
console.log("connected");
});
socket.on('players', (data) => {
const parsedData = JSON.parse(data);
console.log(parsedData);
setPlayers(parsedData);
});
socket.on('artist', (data) => {
setIsArtist(data === userid);
});
socket.on('art-addpic', (data) => {
const parsedData = JSON.parse(data);
console.log(parsedData);
setOptionImages(optionImages =>
// Shallow copy into array, append URL, slice & keep last 4 elements
[...optionImages, parsedData.url].slice(-4),
);
});
return () => {
socket.removeAllListeners();
}
}, []);
useEffect(() => {
if (isArtist) {
console.log('You are an artist, Mr White.');
}
}, [isArtist]);