This project was bootstrapped with Create React App and built with TypeScript, React, and Redux.
Requirement | Support | Additional Details |
---|---|---|
A functioning real-time order book | Full | This includes displaying price, size, total, the spread, and the depth graph |
Order levels are sorted by price | Full | Bids are sorted here and asks are sorted here |
Price levels with a size of 0 are removed | Full | Order removals and updates are calculated here |
Users can switch between the BTC and ETH markets | Full | |
The design mirrors the mockups | Full | |
Responsive orientation changes | None | |
The websocket disconnects when the app isn't in focus | Full | For improved UX the websocket will only disconnect if the app is out of focus for 30+ seconds |
Users can manually reconnect the websocket | Full | |
Re-rendering is variably throttled based on device | Partial | Re-rendering is throttled by a constant here |
Critical flows are tested | Full | Integration tests for OrderBook are here. In a production codebase I'd include more tests. |
The app is publicly hosted | Full | bucky-09-20-21.vercel.app |
Files are organized in "feature folders", with all the Redux logic for a given feature in a single "slice file".
src/
├── app/
├── common/
├── features/
├── App.tsx
├── index.tsx
File/Folder | Purpose |
---|---|
app/ |
Contains store configuration |
common/ |
Contains reusable components, utilities, etc. |
features/ |
Contains "feature folders" which each contain all functionality for a feature |
App.tsx |
The root component |
index.tsx |
The entry point that renders the component tree |
The store is composed of 3 slices of state, 2 middlewares, and an enhancer. The slices of state are: websocket
, activeMarket
, and orderBook
.
{
websocket: {
status: null | 'connecting' | 'connected' | 'disconnected';
feeds: {
[key: string]:
| 'subscribe'
| 'unsubscribe'
| 'subscribed'
| 'unsubscribed';
};
};
activeMarket: {
productId: string;
displayName: string;
};
orderBook: {
bids: {
entities: {
[key: string]: {
price: number;
qty: number;
};
};
ids: Array<number>;
};
asks: {
entities: {
[key: string]: {
price: number;
qty: number;
};
};
ids: Array<number>;
};
snapshotReceived: boolean;
};
}
The middlewares are a Redux Saga middleware and a custom middleware. The custom middleware is used to connect and disconnect the websocket, and to send and receive websocket messages.
The enhancer leverages redux-batched-subscribe
and lodash.throttle
to throttle subscription notifications. By throttling subscription notifications, React re-renders that are triggered due to state changes are also throttled.
- Where should websockets and other persistent connections live?
- How can I reduce the number of store update events?
- Blogged Answers: A Comparison of Redux Batching Techniques
- bitfinexcom/bfx-hf-ui
- AdaptiveConsulting/ReactiveTraderCloud
Run the following commands from the project directory.
- Install the dependencies:
npm install
- Start the app:
npm start