RTW*_*RTW 5 javascript express socket.io reactjs react-hooks
我没有找到任何关于如何使用与 socket.io 反应从快速服务器获取数据的示例。
现在我做这样的事情:Server.js
io.on('connection', socket => {
console.log(socket.id)
socket.on('disconnect', () => {
console.log(socket.id + ' disconnected')
})
socket.on('load settings', () => {
socket.emit('settings is here', data)
})
})
Run Code Online (Sandbox Code Playgroud)
React.js
const [socket] = useState(io())
const [settings, setSettings] = useState(false)
useEffect(() => {
try {
socket.emit('load settings');
socket.on('settings is here', (data) => {
// we get settings data and can do something with it
setSettings(data)
})
} catch (error) {
console.log(error)
}
}, [])
Run Code Online (Sandbox Code Playgroud)
Yan*_*Tay 11
这看起来不错,但有一些事情可以改进,例如在卸载之前断开套接字和不使套接字成为状态的一部分(请参阅下面的代码示例)。
如果您对如何将现有代码移植到钩子感到困惑,请先使用类编写组件,然后将一部分一部分移植到钩子。您可以将此StackOverflow 答案称为备忘单。
使用传统类,使用 socket.io 看起来像:
class App extends React.Component {
constructor(props) {
super(props);
this.socket = io();
}
componentDidMount() {
this.socket.open();
this.socket.emit('load settings');
this.socket.on('settings is here', (data) => {
// we get settings data and can do something with it
this.setState({
settings: data,
})
});
}
componentWillUnmount() {
this.socket.close();
}
render() {
...
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以移植this.socket使用useRef(它不需要state成为你的render()函数的一部分,因为你的函数不需要它。所以useRef是一个更好的选择(尽管useState可能仍然有效)。
端口componentDidMount()经由使用useEffect和传递一个空数组作为第二个参数,使仅在安装运行效果回调。
港口componentWillUnmount()通过返回的回调函数useEffect,其阵营卸载之前将调用回调函数。
function App() {
const socketRef = useRef(null);
const [settings, setSettings] = useState(false);
useEffect(() => {
if (socketRef.current == null) {
socketRef.current = io();
}
const {current: socket} = socketRef;
try {
socket.open();
socket.emit('load settings');
socket.on('settings is here', (data) => {
// we get settings data and can do something with it
setSettings(data);
})
} catch (error) {
console.log(error);
}
// Return a callback to be run before unmount-ing.
return () => {
socket.close();
};
}, []); // Pass in an empty array to only run on mount.
return ...;
}
Run Code Online (Sandbox Code Playgroud)
接受的答案有一个缺点,即每次重新渲染时都会调用 useRef() 的初始状态。例如,对于文本输入,每次输入更改时都会建立新的连接。我想出了两个解决方案:
const ChatInput = () => {
const [chatMessage, setChatMessage] = useState<string>('');
const socket = useRef<Socket>();
useEffect(() => {
socket.current = io('my api');
socket.current.on('chat message', (message: string) => {
setChatMessage(message);
});
return () => { socket.current?.disconnect(); };
}, []);
const inputHandler = (text: string) => {
socket.current?.emit('chat message', text);
};
return (
<View>
<Text>{chatMessage}</Text>
<TextInput onChangeText={(text) => inputHandler(text)} />
</View>
);
};
Run Code Online (Sandbox Code Playgroud)
const ChatInput = () => {
const [chatMessage, setChatMessage] = useState<string>('');
const [socket] = useState(() => io('my api'));
useEffect(() => {
socket.on('chat message', (message: string) => {
setChatMessage(message);
});
return () => { socket.disconnect(); };
}, []);
const inputHandler = (text: string) => {
socket.emit('chat message', text);
};
return (
<View>
<Text>{chatMessage}</Text>
<TextInput onChangeText={(text) => inputHandler(text)}/>
</View>
);
};
export default ChatInput;
Run Code Online (Sandbox Code Playgroud)