![](/img/trans.png)
[英]React infinite rerender, useEffect issue, no set state triggered
[英]React state being set back to initial [] when socket.on() is triggered inside useEffect()
我是 React 功能組件的菜鳥,這是我第一次嘗試使用 socket-io。
我有一個功能組件,它是一個收件箱,每頁從InboxList
數組呈現多達十個“警報”行。 我正在使用 socket-io,以便在單擊特定行時多個客戶端可以實時查看(該行變為灰色)。
問題是大多數情況下,一旦單擊警報,客戶端(觀察行更改,而不是單擊)將使其收件箱為空(InboxList 中的 0 個警報)。
經過一些調試,我發現一旦觸發了 socket.on('alertClicked'),我的 inboxList state 就為空(而不是我期望的相同的 10 個警報)。
這將導致我在inboxListCopy
greyOutAlert()
中的 inboxListCopy 當然為空。
如果有人有建議,將不勝感激。
上下文的功能組件代碼:
import React, { useState, useContext, useEffect } from 'react';
import io from 'socket.io-client';
import Axios from 'axios';
import Table from 'react-bootstrap/Table';
import Pagination from 'react-responsive-pagination';
import { useHistory } from 'react-router-dom';
import '../../App.css';
let socket;
export default function Inbox() {
const [token, setToken] = useState(() => {
return localStorage.getItem('auth-token');
});
const [currentPage, setCurrentPage] = useState(() => {
return 1;
});
const [alertCount, setAlertCount] = useState(() => {
return 5;
});
const [inboxList, setInboxList] = useState(() => {
return [];
});
const history = useHistory();
useEffect(() => {
const connectionOptions = {
"force new connection" : true,
"reconnectionAttempts": "Infinity",
"timeout" : 10000,
"transports" : ["websocket"]
}
socket = io('http://localhost:5000', connectionOptions);
return () => {
socket.emit('disconnected');
socket.off();
}
}, []);
useEffect(()=>{
fetchAlertCount();
},[])
useEffect(()=>{
socket.on('alertClicked', (alertId) => {
greyOutAlert(alertId);
});
},[])
const greyOutAlert = (alertId) => {
let inboxListCopy = [...inboxList];
for (let i = 0; i < inboxListCopy.length; i++) {
if (inboxListCopy[i]._id === alertId) {
inboxListCopy[i].hasBeenReviewed = true;
break;
}
}
setInboxList(inboxListCopy);
};
useEffect(() => {
fetchAlerts();
},[currentPage]);
const fetchAlertCount = async () => {
const config = {
headers: {
'x-auth-token': token,
}
};
const alertCountResponse = await Axios.get('http://localhost:5000/alertinbox/totalAlerts', config);
setAlertCount(alertCountResponse.data.count);
};
const fetchAlerts = async () => {
const config = {
headers: {
'x-auth-token': token,
'page': currentPage
}
};
const alertsResponse = await Axios.get('http://localhost:5000/alertinbox/', config);
setInboxList(alertsResponse.data.alerts);
};
const handleClick = (alertId, messageType) => {
socket.emit('clientClickedAlert', {alertId});
switch (messageType) {
case '2+ Minutes':
history.push(`/2plusminutes/${alertId}`, {alertId});
break;
case 'SOS':
history.push(`/sos/${alertId}`, {alertId});
break;
case 'Low Battery':
history.push(`/lowbattery/${alertId}`, {alertId});
break;
};
};
return (
<React.Fragment>
<div id='inbox'>
<Table>
<thead>
<tr>
<th>Alert Type</th>
<th>Customer Name</th>
<th>Timestamp</th>
<th>Vehicle</th>
</tr>
</thead>
<tbody>
{inboxList.map(function(alert, index){
return(
<tr key={index} onClick={() => handleClick(alert._id, alert.messageType)} className={alert.hasBeenReviewed ? 'darken' : 'lighten'}>
<td>{alert.messageType}</td>
<td>{alert.ownerName}</td>
<td>{alert.createdAt}</td>
<td>{alert.vehicle.year + ' ' + alert.vehicle.make + ' ' + alert.vehicle.model}</td>
</tr>
)
})}
</tbody>
</Table>
</div>
<Pagination
current={currentPage}
total={Math.ceil(alertCount/10)}
onPageChange={setCurrentPage}
maxWidth={100}
/>
</React.Fragment>
)
}
我建議您將確切的初始 state 傳遞給 useState 掛鈎,而不是像下面的 function :
const [inboxList, setInboxList] = useState([]);
好吧,我想通了。 如果您需要更新 state 的東西,而新的 state 依賴於以前的 state,請確保使用功能更新。
在我的代碼中,我需要當前的 inboxList state(實際上是之前的 state,因為 useEffect() 在渲染后運行)來計算新的 inboxList Z9ED39E2EA931586B6A985A6942EF57 為了實現這一點,我使用了作為 React 的 useState 鈎子一部分的可選回調。
正確的代碼(useEffect() 方法更新):
useEffect(()=>{
socket.on('alertClicked', (alertId) => {
setInboxList(inboxList => {
let inboxListCopy = [...inboxList];
for (let i = 0; i < inboxListCopy.length; i++) {
if (inboxListCopy[i]._id === alertId) {
inboxListCopy[i].hasBeenReviewed = true;
break;
}
}
return inboxListCopy;
});
});
},[])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.