Sharing Websocket In React Components
Note - This content in this post is a bit outdated. Check out the official docs for the Context API.
Often times there is a requirement to share a common websocket connection between React components. I have been using the React Context API to do that. Example for socket.io:
In this case there is a top level component file App.js
where the socket is initialized and then made available to other React Components like HomePageComponent.js
(which are its children) using Context.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import React, { Component, PropTypes } from "react";
import io from "socket.io-client";
class App extends Component {
constructor(props, context) {
super(props, context);
this.state = {
message: null
};
this.socket = io("https://localhost:3001");
}
getChildContext() {
return {
socket: this.socket
};
}
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
App.propTypes = {
children: PropTypes.object.isRequired
};
App.childContextTypes = {
socket: PropTypes.object.isRequired
};
export default App;
A common pattern while using Context is to write a Provider
for the children. In that case, after initializing the websocket in App.js
, any other component(s) can be provided access to the websocket via its props by wrapping it in the provider like this:
1
2
3
4
5
6
7
8
render() {
return (
<SocketProvider>
<MyComponent1 />
<MyComponent2 />
</SocketProvider>
);
}
Here the SocketProvider
is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React, { Component, PropTypes } from "react";
class SocketProvider extends Component {
constructor(props, context) {
super(props, context);
this.socket = context.socket;
}
render() {
return (
<span>
{React.cloneElement(this.props.children, {
...this.props,
...{ socket: this.socket }
})}
</span>
);
}
}
SocketProvider.contextTypes = {
socket: PropTypes.object.isRequired
};
export default SocketProvider;
and is accessible in MyComponent1
and MyComponent2
as this.props.socket
. Note that this SocketProvider
only provides the websocket one level deep - children of MyComponent1
do not get to use the websocket unless they are wrapped in SocketProvider
themsevles. Also note that {...this.props, { socket: this.socket }}
is a shallow merge.