So I was tasked with building a component that connects to a WebSocket API to fetch a data stream from Bitstamp, you can check the API docs here. The main reason for going with a Websocket API rather than a Fetch API was to get realtime data. This article illustrates how I went about it.
What is a WebSocket API?
According to MDN, the WebSocket API is an advanced technology that makes it possible to open a two-way interactive communication session between the user's browser and a server. With the WebSocket API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply. This link explains the differences between a WebSocket API and a FETCH API.
In this app, we'll be fetching a live order book stream from the bitstamp API. You can view the complete app on Code Sandbox
Setting up React
I'll be using create-react-app for creating the react app. So fire up your command line and let's start working:
npx create-react-app orderbook
Once it is done open the root directory with cd orderbook
and run npm start
to be sure the app is working.
We'll refactor and get rid of the boilerplate code that we won't need. Run cd src
to switch to the src directory and then run rm serviceWorker.js logo.svg
to delete serviceWorker.js
and logo.svg
. The app will crash after doing this because index.js
and App.js
imported the files that were deleted. Refactor your index.js
to look like this:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
and App.js
to look this way:
import React from 'react';
import './App.css';
const App = () => {
return (
<div>
<h2> Crypto Order Book </h2>
</div>
)
}
export default App;
At this point, the react-app should be working and displaying Crypto Order Book in the browser
Creating the OrderBook Component
Create an OrderBook component in the src file
cd src
touch OrderBook.js
Time to get our hands dirty. We would be using react hooks
OrderBook.js
import React, { useState, useEffect } from 'react';
const OrderBook = () => {
const [orders, setOrders] = useState([]);
const currencyPair = 'btcusd';
const currencyArray = currencyPair.toUpperCase().match(/.{1,3}/g);
useEffect(() => {
const subscribe = {
event: 'bts:subscribe',
data: {
channel: `order_book_${currencyPair}`
}
};
const ws = new WebSocket('wss://ws.bitstamp.net');
ws.onopen = () => {
ws.send(JSON.stringify(subscribe));
};
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
setOrders(response.data);
};
ws.onclose = () => {
ws.close();
};
return () => {
ws.close();
};
}, [currencyPair]);
const { bids, asks } = orders;
const orderRows = (arr) =>
arr &&
arr.map((item, index) => (
<tr key={index}>
<td> {item[1]} </td>
<td> {item[0]} </td>
</tr>
));
const orderHead = (title) => (
<thead>
<tr>
<th colSpan="2">{title}</th>
</tr>
<tr>
<th>Amount ({currencyArray[0]})</th>
<th>Price ({currencyArray[1]})</th>
</tr>
</thead>
);
return (
<div className="order-container">
<table>
{orderHead('Bids')}
<tbody>{orderRows(bids)}</tbody>
</table>
<table>
{orderHead('Asks')}
<tbody>{orderRows(asks)}</tbody>
</table>
</div>
);
};
export default OrderBook;
We import React, useState, and useEffect. If you have no idea about useState and useEffect I suggest you check the React documentation on hooks here
The next thing we do is to create our orders
state, initialize our currencyPair
to btcusd, split the currency pair into separate currencies and store in currencyArray
.
const [orders, setOrders] = useState([]);
const currencyPair = 'btcusd';
const currencyArray = currencyPair.toUpperCase().match(/.{1,3}/g);
Next, we want to make sure that when the component mounts and updates it fetches the data from the WebSocket API:
useEffect(() => {
const subscribe = {
event: 'bts:subscribe',
data: {
channel: `order_book_${currencyPair}`
}
};
const ws = new WebSocket('wss://ws.bitstamp.net');
ws.onopen = () => {
ws.send(JSON.stringify(subscribe));
};
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
setOrders(response.data);
};
ws.onclose = () => {
ws.close();
};
return () => {
ws.close();
};
}, [currencyPair]);
We initialize ws
to be an instance of the WebSocket connection. Then we send a subscription message when the onopen
event is called. The onopen
event is an event that is fired whenever the WebSocket is open.
onmessage
event is fired to get data back from the server and store it in our orders
state.
Whenever the onclose
event is fired we terminate the connection to the WebSocket with ws.close()
. After that, we clean up so as not to have a memory leak.
return () => {
ws.close();
};
If you noticed we didn't import the OrderBook in the App component. We will do that now. So open the App component it should look like this:
App.js
import React from 'react';
import OrderBook from './OrderBook';
import './App.css';
const App = () => {
return (
<div>
<h2>Crypto Order Book </h2>
<OrderBook/>
</div>
)
}
export default App;
Then we add a little styling to App.css
to beautify it
App.css
.order-container {
display: flex;
width: 100%;
}
table {
border-collapse: collapse;
width: 100%;
text-align: center;
}
h1,
h2 {
text-align: center;
}
td,
th {
padding: 6px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
tr:hover {
background-color: #ddd;
}
After that save and open your browser you should be seeing a data stream of currency orders.
Top comments (2)
Thank you. I like the no non-sense style of your writing.
I wrote the following code in my project.
const ws = new WebSocket(
"wss://(my api)"
);
But I have WebSocket connection is fail. please take a lot at attached photo.