更新组件时如何不创建到 scoket.io 的新连接?
How not to create a new connection to scoket.io when updating a component?
服务器:
io.on('connection', (socket) => {
const username = socket.id;
socket.emit('connection', username);
socket.emit(
'products',
JSON.parse(fs.readFileSync(`${path.join(__dirname)}/db.json`, 'utf-8'))
);
socket.on('update', (data) => {
console.log(data);
const { id, value, replace } = data;
const products = JSON.parse(
fs.readFileSync(`${path.join(__dirname)}/db.json`, 'utf-8')
);
products.map((item) => {
if (item.id === id) {
item[replace] = value;
}
return item;
});
fs.writeFileSync(
`${path.join(__dirname)}/db.json`,
JSON.stringify(products)
);
socket.emit('products', products);
});
});
我的组件:
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import socketClient from 'socket.io-client';
import Table from '../components/TableProducts';
import { updateDataTable, getData } from '../redux/actions/products';
import { getProducts } from '../redux/selectors/products';
const TableContainer = () => {
const dispatch = useDispatch();
const products = useSelector((state) => getProducts(state.products));
const socket = socketClient.connect('http://localhost:9000/');
useEffect(() => {
socket.on('products', (data) => {
dispatch(getData(data));
});
}, []);
const handleChange = (object) => {
// const {id, name, value} = data;
dispatch(updateProduct(object));
socket.emit('update', object);
}
return (
<Table data={products} />
);
};
export default TableContainer;
执行handleChange后,我的套接字被发送到服务器,一切都在那里处理得很好。问题是显然我的组件在从服务器接收套接字时更新,从而执行 useEffect 创建新连接。
更新(添加我的 index.js 文件):
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import 'bootstrap/dist/css/bootstrap.min.css';
import './scss/_base.scss';
import store from './redux/store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
连接被多次触发可能是因为组件每次都在您的应用程序中重新安装并触发 const socket = socketClient.connect('http://localhost:9000/');
。您可以使用 React Context 来更改该行为并以这种方式访问应用程序中任何组件中的套接字实例:
socket.js
import React from "react";
import io from "socket.io-client";
export const socket = io("http://localhost:9000/");
export const SocketContext = React.createContext();
index.js
import { SocketContext, socket } from "./socket";
ReactDOM.render(
<React.StrictMode>
<SocketContext.Provider value={socket}>
<App />
</SocketContext.Provider>
</React.StrictMode>,
document.getElementById("root")
);
component.js
import React from "react";
import { SocketContext } from "./socket";
export const TableContainer = () => {
const socket = React.useContext(SocketContext);
...
}
这样,连接被触发一次。
服务器:
io.on('connection', (socket) => {
const username = socket.id;
socket.emit('connection', username);
socket.emit(
'products',
JSON.parse(fs.readFileSync(`${path.join(__dirname)}/db.json`, 'utf-8'))
);
socket.on('update', (data) => {
console.log(data);
const { id, value, replace } = data;
const products = JSON.parse(
fs.readFileSync(`${path.join(__dirname)}/db.json`, 'utf-8')
);
products.map((item) => {
if (item.id === id) {
item[replace] = value;
}
return item;
});
fs.writeFileSync(
`${path.join(__dirname)}/db.json`,
JSON.stringify(products)
);
socket.emit('products', products);
});
});
我的组件:
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import socketClient from 'socket.io-client';
import Table from '../components/TableProducts';
import { updateDataTable, getData } from '../redux/actions/products';
import { getProducts } from '../redux/selectors/products';
const TableContainer = () => {
const dispatch = useDispatch();
const products = useSelector((state) => getProducts(state.products));
const socket = socketClient.connect('http://localhost:9000/');
useEffect(() => {
socket.on('products', (data) => {
dispatch(getData(data));
});
}, []);
const handleChange = (object) => {
// const {id, name, value} = data;
dispatch(updateProduct(object));
socket.emit('update', object);
}
return (
<Table data={products} />
);
};
export default TableContainer;
执行handleChange后,我的套接字被发送到服务器,一切都在那里处理得很好。问题是显然我的组件在从服务器接收套接字时更新,从而执行 useEffect 创建新连接。
更新(添加我的 index.js 文件):
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import 'bootstrap/dist/css/bootstrap.min.css';
import './scss/_base.scss';
import store from './redux/store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
连接被多次触发可能是因为组件每次都在您的应用程序中重新安装并触发 const socket = socketClient.connect('http://localhost:9000/');
。您可以使用 React Context 来更改该行为并以这种方式访问应用程序中任何组件中的套接字实例:
socket.js
import React from "react";
import io from "socket.io-client";
export const socket = io("http://localhost:9000/");
export const SocketContext = React.createContext();
index.js
import { SocketContext, socket } from "./socket";
ReactDOM.render(
<React.StrictMode>
<SocketContext.Provider value={socket}>
<App />
</SocketContext.Provider>
</React.StrictMode>,
document.getElementById("root")
);
component.js
import React from "react";
import { SocketContext } from "./socket";
export const TableContainer = () => {
const socket = React.useContext(SocketContext);
...
}
这样,连接被触发一次。