I am getting an error 'TypeError: this.props.data.map is not a function' on clicking 'Start Streaming Data' button.
App.tsx code
import React, { Component } from 'react';
import DataStreamer, { ServerRespond } from './DataStreamer';
import Graph from './Graph';
import './App.css';
/
State declaration for /
interface IState {
data: ServerRespond[],
}
/
The parent element of the react app.
It renders title, button and Graph react element.
/
class App extends Component<{}, IState> {
constructor(props: {}) {
super(props);
this.state = {
// data saves the server responds.
// We use this state to parse data down to the child element (Graph) as element property
data: [],
};
}
/
Render Graph react component with state.data parse as property data
/
renderGraph() {
return ()
}
/
Get new data from server and update the state with the new data
/
getDataFromServer() {
DataStreamer.getData((serverResponds: ServerRespond[]) => {
// Update the state by creating a new array of data that consists of
// Previous data in the state and the new data from server
this.setState({ data: {...this.state.data, ...serverResponds} });
});
}
/
Perspective library adds load to HTMLElement prototype.
This interface acts as a wrapper for Typescript compiler.
/
interface PerspectiveViewerElement {
load: (table: Table) => void,
}
/
React component that renders Perspective based on data
parsed from its parent through data property.
/
class Graph extends Component<IProps, {}> {
// Perspective table
table: Table | undefined;
componentDidMount() {
// Get element to attach the table from the DOM.
const elem: PerspectiveViewerElement = document.getElementsByTagName('perspective-viewer')[0] as unknown as PerspectiveViewerElement;
const schema = {
stock: 'string',
top_ask_price: 'float',
top_bid_price: 'float',
timestamp: 'date',
};
if (window.perspective && window.perspective.worker()) {
this.table = window.perspective.worker().table(schema);
}
if (this.table) {
// Load the `table` in the `<perspective-viewer>` DOM reference.
// Add more Perspective configurations here.
elem.load(this.table);
}
}
componentDidUpdate() {
// Everytime the data props is updated, insert the data into Perspective table
if (this.table) {
// As part of the task, you need to fix the way we update the data props to
// avoid inserting duplicated entries into Perspective table again.
this.table.update(this.props.data.map((el: any) => {
// Format the data from ServerRespond to the schema
return {
stock: el.stock,
top_ask_price: el.top_ask && el.top_ask.price || 0,
top_bid_price: el.top_bid && el.top_bid.price || 0,
timestamp: el.timestamp,
};
}));
}
}
}
export default Graph;
DataStreamer.ts code
export interface Order {
price: Number,
size: Number,
}
/
The datafeed server returns an array of ServerRespond with 2 stocks.
We do not have to manipulate the ServerRespond for the purpose of this task.
/
export interface ServerRespond {
stock: string,
top_bid: Order,
top_ask: Order,
timestamp: Date,
}
/
Send request to the datafeed server and executes callback function on success
@param callback callback function that takes JSON object as its argument
/
static getData(callback: (data: ServerRespond[]) => void): void {
const request = new XMLHttpRequest();
request.open('GET', DataStreamer.API_URL, false);
I am getting an error 'TypeError: this.props.data.map is not a function' on clicking 'Start Streaming Data' button.
App.tsx code
import React, { Component } from 'react'; import DataStreamer, { ServerRespond } from './DataStreamer'; import Graph from './Graph'; import './App.css';
/ State declaration for
/
interface IState {
data: ServerRespond[],
}
/ The parent element of the react app. It renders title, button and Graph react element. / class App extends Component<{}, IState> { constructor(props: {}) { super(props);
}
/ Render Graph react component with state.data parse as property data / renderGraph() { return ()
}
/ Get new data from server and update the state with the new data / getDataFromServer() { DataStreamer.getData((serverResponds: ServerRespond[]) => { // Update the state by creating a new array of data that consists of // Previous data in the state and the new data from server this.setState({ data: {...this.state.data, ...serverResponds} }); }); }
/ Render the App react component / render() { return (
} }
export default App;
Graph.tsx code
import React, { Component } from 'react'; import { Table } from '@jpmorganchase/perspective'; import { ServerRespond } from './DataStreamer'; import './Graph.css';
/ Props declaration for
/
interface IProps {
data: ServerRespond[],
}
declare const window: any;
/ Perspective library adds load to HTMLElement prototype. This interface acts as a wrapper for Typescript compiler. / interface PerspectiveViewerElement { load: (table: Table) => void, }
/ React component that renders Perspective based on data parsed from its parent through data property. / class Graph extends Component<IProps, {}> { // Perspective table table: Table | undefined;
render() { return React.createElement('perspective-viewer'); }
componentDidMount() { // Get element to attach the table from the DOM. const elem: PerspectiveViewerElement = document.getElementsByTagName('perspective-viewer')[0] as unknown as PerspectiveViewerElement;
}
componentDidUpdate() { // Everytime the data props is updated, insert the data into Perspective table
} }
export default Graph;
DataStreamer.ts code
export interface Order { price: Number, size: Number, } / The datafeed server returns an array of ServerRespond with 2 stocks. We do not have to manipulate the ServerRespond for the purpose of this task. / export interface ServerRespond { stock: string, top_bid: Order, top_ask: Order, timestamp: Date, }
class DataStreamer { // The url where datafeed server is listening static API_URL: string = 'http://localhost:8080/query?id=1';
/ Send request to the datafeed server and executes callback function on success @param callback callback function that takes JSON object as its argument / static getData(callback: (data: ServerRespond[]) => void): void { const request = new XMLHttpRequest(); request.open('GET', DataStreamer.API_URL, false);
} }
export default DataStreamer;