insidesherpa / JPMC-tech-task-2

29 stars 201 forks source link

Graph.tsx TypeError: this.props.data.map is not a function #322

Closed RicaGhosh closed 3 years ago

RicaGhosh commented 3 years ago

I am getting an error 'TypeError: this.props.data.map is not a function' on clicking 'Start Streaming Data' button. 2021-07-25 (1)

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} }); }); }

/ Render the App react component / render() { return (

Bank & Merge Co Task 2
{this.renderGraph()}
)

} }

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;

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, }

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);

request.onload = () => {
  if (request.status === 200) {
    callback(JSON.parse(request.responseText));
  } else {
    alert ('Request failed');
  }
}

request.send();

} }

export default DataStreamer;