I didn't found any examples about how to fetch data from express server using react with socket.io.
Now i do something like this: 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)
})
})
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)
}
}, [])
I didn't found any examples about how to fetch data from express server using react with socket.io.
Now i do something like this: 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)
})
})
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)
}
}, [])
Share
Improve this question
edited Nov 20, 2018 at 4:46
Yangshun Tay
53.1k33 gold badges123 silver badges150 bronze badges
asked Nov 19, 2018 at 22:06
ZiiMakcZiiMakc
36.8k25 gold badges74 silver badges121 bronze badges
3
|
2 Answers
Reset to default 14This looks fine, but there are some things you can improve on, such as disconnecting the socket before unmounting and not making the socket part of state (refer to the code example below).
If you're confused over how to port existing code to hooks, write out the component using classes first, then port part by part to hooks. You could refer to this StackOverflow answer as a cheatsheet.
Using traditional classes, using socket.io looks like:
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() {
...
}
}
Then you can port the this.socket
to use useRef
(it doesn't need to be part of state
as your render()
function doesn't need it. So useRef
is a better alternative (although useState
is likely to still work).
Port componentDidMount()
via using useEffect
and passing an empty array as the second argument to make the effect callback only run on mount.
Port componentWillUnmount()
via returning a callback function in the useEffect
callback which React will call before unmounting.
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 ...;
}
The accepted answer has the downside, that the initial state of the useRef() gets called on every re-render. With a text input for example, a new connection is established on every input change. I came up with two solutions:
- Define the socket in the useEffect
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>
);
};
- Define the socket.io in a useState()
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;
useEffect
. It diffs variables passed into that array to decide whether or not to execute the effect callback. – James Commented Nov 19, 2018 at 22:09