Unable to render data from API in React, no errors displayed - javascript

I am using Django Rest Framework to send data to React app. But the data is being shown on screen.
The code isnt returning any errors thus making it difficult to see whats going wrong. This is my second React project thus i am not too familiar with React & JS as of now.
This is my code:
import { render } from "#testing-library/react";
import axios from "axios";
import React, { Component, useState, useEffect } from "react";
const api_url = "http://localhost:8000/api/CBView/"
class StocksHomePage extends Component {
constructor(props) {
super(props);
this.state = {
isFetching:false,
data_s :[]
};
}
componendDidMount() {
this.fetchData();
this.timer = setInterval(() => this.fetchData(), 50);
}
fetchData = () => {
this.setState({...this.state, isFetching:true});
axios.get(api_url)
.then (response => {
this.setState({data_s:response.data[0]})
})
.catch(e => {
console.log(e);
this.setState({...this.state, isFetching:false});
});
};
render() {
return (
<div>
{this.state.data_s.map(m => <p>{m.co_S}</p>)}
{/* <p data={this.state.data_s.co_S} ></p> */}
<ul>
<li isKey dataField='co_N'></li>
<li dataField='co_S'></li>
<li dataField='price'></li>
</ul>
<p>{this.state.isFetching ? 'Fetching users...' : ''}</p>
</div>
)
}
}

I fixed the issue, all i had to do was include maps function with variable to represent those values. Here is my code:
class StocksHomePage extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
loaded: false,
placeholder: "loading"
};
}
componentDidMount() {
axios
.get("http://localhost:8000/CBView")
.then(response => {return response.data; })
.then(data => {this.setState(() => {
return {data, loaded:true};
});
});
}
handleClick = (props) => {
<HashRouter>
<Route path='/StocksDetail' component={StocksDetail} />
</HashRouter>
};
render() {
return (
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Price/ Chng</th>
<th>Mkt Cap</th>
<th>Volume</th>
<th>Turnover</th>
</tr>
</thead>
<tbody>
{this.state.data.map(item => {
return (
<tr key={item.co_S}>
<button onCLick={this.handleClick(item.co_S)}><td >{item.co_N}</td></button>
<td>{item.price}</td>
<td>{item.p_chng_pc}</td>
<td>{item.Mkt_cap}</td>
<td>{item.volume}</td>
<td>{item.volume * item.price}</td>
</tr>
);
})};
</tbody>
</table>
);
}
}
export default StocksHomePage;

Related

Prevent reinitialization of React tooltip component to prevent API calls

I load profile data from API to be displayed when the client hovers over a profile name. When the client stops hovering and then hovers again, the tooltip component gets reinitialized and an API call is done again. Currently I am using localStorage to cache the data but this seems like an improper fix.
My question is how do I prevent the tooltip component from being thrown away and reinitialized?
const renderTooltip = (props) => (
<Tooltip>
<UserInfoFetchData uuid={props} />
</Tooltip>
);
<OverlayTrigger
placement="top"
uuid={gamer.uuid}
delay={{ show: 250, hide: 400 }}
overlay={renderTooltip(gamer.uuid)}
>
<a href={"/user/" + gamer.uuid}>{gamer.username}</a>
</OverlayTrigger>
The above code is used to call the React Component. Below you see the code of the component itself.
import React, { useEffect, useState } from "react";
import Backend from "../../data/Backend";
export default class UserInfoFetchData extends React.Component {
constructor(props) {
super(props);
console.log("test");
this.state = {};
}
componentDidMount() {
const cacheLocation = "profile " + this.props.uuid;
let data = localStorage.getItem(cacheLocation);
if (!data) {
this.controller = new AbortController();
new Backend()
.getUser({ uuid: this.props.uuid }, { signal: this.controller.signal })
.then((response) => {
console.log("fetched data");
this.setState(response.data);
localStorage.setItem(cacheLocation, JSON.stringify(response.data));
this.controller = null;
});
} else {
this.setState(JSON.parse(data));
}
}
componentWillUnmount() {
if (this.controller) {
this.controller.abort();
}
}
render() {
const capitalize = (str) => {
return `${str[0].toUpperCase()}${str.slice(1)}`;
};
return (
<div className="card border-dark ">
<div className="card-body">
<table className="table table-hover">
<tbody>
{Object.keys(this.state)
.filter(
(o) =>
o !== "uuid" &&
o !== "username" &&
!o.includes("weekly") &&
!o.includes("monthly")
)
.map((e, i) => {
return (
<tr key={e}>
<th scope="row">{capitalize(e.replace("_", " "))}</th>
<td>{this.state[e]}</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
}
}
The console logs "test" each time I hover over a username, which means the component is being reinitialized each time. Is there a way I can make this only initialize once? Or is there a way to properly store the API retrieved data in the class?
Note: new Backend().getUser() simply returns an AxioInstance.

JS/React - Live Search Bar With Mapping

After two days of being stuck on this component, I'm asking for any sort of help. I'm trying to search an API based on user input, and then filter that down to a more specific option as the user keeps typing. After solving a dozen or so errors, I'm still left with "Can't find variable 'Query'", and I just can't seem to find or figure out what exactly it's wanting. There was another post on here that led me in the right direction, but didn't provide any sort of answer for the issue I'm having. Any help here would be appreciated.
import axios from "axios";
import axiosRateLimit from "axios-rate-limit";
import React, { Component } from "react";
import SearchBar from "react-native-elements/dist/searchbar/SearchBar-ios";
class CardSearch extends Component {
state = {
data: [],
filteredData: [],
query: "",
};
handleInputChange = (event) => {
const query = event.target.value;
this.setState((prevState) => {
const filteredData = prevState.data.filter((element) => {
return element.name.toLowerCase().includes(query.toLowerCase());
});
return {
query,
filteredData,
};
});
};
getData = () => {
axiosRateLimit(
axios.get(`https://api.scryfall.com/cards/autocomplete?q=${query}`),
{ maxRPS: 8 }
)
.then((response) => response.json())
.then((data) => {
const { query } = this.state;
const filteredData = data.filter((element) => {
return element.name.toLowerCase().includes(query.toLowerCase());
});
this.setState({
data,
filteredData,
});
});
};
componentWillMount() {
this.getData();
}
render() {
return (
<>
<SearchBar
placeholder='Search For...'
value={this.state.query}
onChange={this.handleInputChange}
/>
<div>
{this.state.filteredData.map((i) => (
<p>{i.name}</p>
))}
</div>
</>
);
}
}
export default CardSearch;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Have a look at this Link. You are not setting the State in a Constructor. And as already mentioned in the comments you will then have to access the query using this.state.query
https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
The Code-Sample from the React Documentation:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}

React setState() needs 2 clicks to update UI

I'm new in React. My question may be common in React developers and there are many same questions but I still don't know how to resolve that. I must still click twice to update UI state. The first click just calls event handler but not update counter variable in state. Even I used the callback form of setState() like the following:
this.setState({ hasButtonBeenClicked: true }, () => {console.log("Clicked")});
the console.log("Clicked") was not reached in first click as well!
App.js
import React, { Component, useState } from "react";
import { Summary } from "./Summary";
import ReactDOM from "react-dom";
let names = ["Bob", "Alice", "Dora"]
function reverseNames() {
names.reverse();
ReactDOM.render(<App />, document.getElementById('root'));
}
function promoteName(name) {
names = [name, ...names.filter(val => val !== name)];
ReactDOM.render(<App />, document.getElementById('root'));
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
}
incrementCounter = (increment) => this.setState({counter: this.state.counter + increment});
render() {
return (
<table className="table table-sm table-striped">
<thead>
<tr><th>#</th><th>Name</th><th>Letters</th></tr>
</thead>
<tbody>
{names.map((name, index) =>
<tr key={name}>
<Summary index={index} name={name}
reverseCallback={() => reverseNames()}
promoteCallback={() => promoteName(name)}
counter={this.state.counter}
incrementCallback={this.incrementCounter}
/>
</tr>
)}
</tbody>
</table>
)
}
}
Summary Component
import React, { Component } from "react";
import { SimpleButton } from "./SimpleButton";
export class Summary extends Component {
render() {
const props = this.props;
return (
<React.Fragment>
<td>{props.index + 1} </td>
<td>{props.name} </td>
<td>{props.name.length} </td>
<td>
<SimpleButton
className="btn btn-warning btn-sm m-1"
callback={() => props.reverseCallback()}
text={`Reverse (${props.name})`}
{...this.props}
/>
</td>
</React.Fragment>
)
}
}
SimpleButton
import React, { Component } from "react";
export class SimpleButton extends Component {
constructor(props) {
super(props);
this.state = {
hasButtonBeenClicked: false
}
}
handleClick = (e) => {
this.props.incrementCallback(3);
this.setState({ hasButtonBeenClicked: true });
this.props.callback();
console.log(e);
}
render() {
return (
<button onClick={(e) => this.handleClick(e)}
className={this.props.className}
disabled={this.props.disabled === "true"
|| this.props.disabled === true}>
{ this.props.text} { this.props.counter}
{ this.state.hasButtonBeenClicked &&
<div>Button Clicked!</div>
}
</button>
)
}
}
I resolved the problem by commenting out the line in App.js
function reverseNames() {
names.reverse();
// ReactDOM.render(<App />, document.getElementById('root'));
}
I thinks the line making app rerender before the actual state updated so I was behind the actual state 1 span. The first click is the initial state, the second click is the state after the first click .etc

Sending API data in Gatsby to be used in Chart.js

I am trying to send API data being called from my index.js to my ChartData.js. index.js is a page and ChartData.js is a component in Gatsby, so to begin with I could not figure out if Gatsby's Link to="" function only work from one page to another or if it can send data from a page to a component.
The issue is when I try to access the sent data from index.js to ChartData.js in the line {props.location.state.companyName} I am getting the error: TypeError: props.location is undefined
I plan to switch out labels: ['x', 'y'] for something like labels: [{props.location.state.companyName}, {props.location.state.symbol} etc. I am not sure if this would be the correct syntax either.
A more detailed explanation here: https://www.youtube.com/watch?v=No9cqzqlKS0&feature=youtu.be
index.js:
import React from "react"
import { Link } from "gatsby"
import axios from "axios"
import "../css/style.css"
import Layout from "../components/layout"
import { symbol } from "prop-types"
import ChartData from "../components/ChartData"
export default class index extends React.Component {
state = {
companyName: "",
previousClose: "",
marketCap: "",
change: "",
symbol: "",
topStocks: [],
Yearweekhigh: "",
Yearweeklow: "",
avgTotalVolume: "",
peRatio: ""
}
componentDidMount() {
const API_KEY = '*******************';
axios.get(`https://cloud.iexapis.com/stable/stock/market/previous?token=${API_KEY}`)
.then(res => {
console.log(res)
const topStocks = res.slice(1);
this.setState({ topStocks })
})
}
clickHandler = (event) => {
if (event.keyCode === 13) {
const query = event.target.value;
const API_KEY = '*******************';
axios.get(`https://cloud.iexapis.com/stable/stock/${query}/quote?token=${API_KEY}`)
.then(res => {
const companyName = res.data['companyName'];
this.setState({ companyName })
const previousClose = res.data['previousClose'];
this.setState({ previousClose })
const marketCap = res.data['marketCap'];
this.setState({ marketCap })
const change = res.data['change'];
this.setState({ change })
const symbol = res.data['symbol'];
this.setState({ symbol })
const Yearweekhigh = res.data['week52High'];
this.setState({ Yearweekhigh })
const Yearweeklow = res.data['week52Low'];
this.setState({ Yearweeklow })
const avgTotalVolume = res.data['avgTotalVolume'];
this.setState({ avgTotalVolume })
const peRatio = res.data['peRatio'];
this.setState({ peRatio })
})
}
}
render() {
return (
<Layout>
<div class = "main-div">
<input type="search" class="main-search" onKeyDown={event => this.clickHandler(event)}/>
<table>
<tr>
<th>Ticker-Symbol</th>
<th>Market Cap</th>
<th>Previous Close</th>
</tr>
<tr>
<td>
<Link to='/details/' state={{
setState: this.state.symbol,
companyName: this.state.companyName,
previousClose: this.state.previousClose,
marketCap: this.state.marketCap,
change: this.state.change,
Yearweekhigh: this.state.Yearweekhigh,
Yearweeklow: this.state.Yearweeklow,
avgTotalVolume: this.state.avgTotalVolume,
peRatio: this.state.peRatio
}}>
{this.state.symbol}</Link>
<Link to='/ChartData/' state={{
setState: this.state.symbol,
companyName: this.state.companyName,
previousClose: this.state.previousClose,
marketCap: this.state.marketCap,
change: this.state.change,
Yearweekhigh: this.state.Yearweekhigh,
Yearweeklow: this.state.Yearweeklow,
avgTotalVolume: this.state.avgTotalVolume,
peRatio: this.state.peRatio
}}></Link>
</td>
<td>{this.state.marketCap}</td>
<td>{this.state.previousClose}</td>
</tr>
</table>
</div>
<div>
{
this.state.topStocks.length && this.state.topStocks.map(stock => (
<h1>{stock.symbol}</h1>
))
}
</div>
<ChartData />
</Layout>
)
}
}
details.js
//import { Link } from "gatsby"
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import Layout from '../components/layout';
import "../css/style.css"
const Details = props => {
const [yourState, setYourState] = useState('');
useEffect(() => {
}, []);
return <Layout>
<div>
<h1 class="details-company-name">{props.location.state.companyName}</h1>
<div class = "details-div">
<div class="details-div-1">
<p>Open {} </p>
<p>High {} </p>
<p>Low {} </p>
<p>52 WK HIGH <h2>{props.location.state.Yearweekhigh}</h2> </p>
<p>52 WK LOW <h2>{props.location.state.Yearweeklow}</h2> </p>
</div>
<div class="details-div-2">
<p>VOLUME</p>
<p>AVG VOL <h2>{props.location.state.avgTotalVolume}</h2> </p>
<p>MKT CAP <h2>{props.location.state.marketCap}</h2></p>
<p>P/E RATIO <h2>{props.location.state.peRatio}</h2></p>
<p>DIV/YIELD</p>
</div>
</div>
</div>
</Layout>;
};
export default Details;
ChartData.js
import React, {useState, useEffect } from "react";
import { Line } from "react-chartjs-2";
const ChartData = props => {
const [yourState, setYourState] = useState('');
const chart = () => {
setYourState({
labels: ['x', 'y'],
datasets: [
{
level: 'level of xyz',
data: [22, 55]
}
]
})
}
useEffect(() => {
chart()
}, [])
return(
<div>
<h1>Hello</h1>
{props.location.state.companyName}
<div>
<Line data={yourState}/>
</div>
</div>
)
}
export default ChartData;
There's a quite a bit going on here that needs clarification. You mention graphql in the title, but there's no graphql in your code.
You are using axios to fetch data at runtime in the componentDidMount lifecycle method, and then setting the result to state.
I assume that once you have that data, all you want to do is pass it to your chart component so that it can render itself on the index page.
Consider the following example which does the same thing; Fetches some data from the Rick & Morty api, sets the results to state, and passes the relevant part of that state via props directly to the <Characters /> component.
From there, the <Characters /> component has everything it needs in order to render. (It has no state, and is not concerned about where the data actually came from).
// index.js
import React from 'react';
import './App.css';
import Characters from './Characters'
const api = "https://rickandmortyapi.com/api/character/";
class IndexPage extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch(api)
.then(res => res.json())
.then(
json => {
console.log(json)
this.setState({
isLoaded: true,
data: json.results
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
error => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<Characters data={data} />
);
}
}
}
export default IndexPage;
// Characters.js
import React from 'react';
class Characters extends React.Component {
render() {
return (
<ul>
{this.props.data.map(item => (
<li key={item.id}>
<dl>
<dt>Name:</dt>
<dd>{item.name}</dd>
<dt>Species:</dt>
<dd>{item.species}</dd>
<dt>Status:</dt>
<dd>{item.status}</dd>
</dl>
</li>
))}
</ul>
);
}
}
export default Characters;
Codesandbox Example using functional components and hooks
Gatsby’s <Link> component allows you to link between pages (and does some other stuff like prefetching resources, and can share data between pages). As you are rendering the <ChartData /> component on the index page, this is not required to solve your problem.
Using <Link> with state works because details is a gatsby page. As <ChartData> is not a page, you can't *link* to it.

React render not rendering my data from api

I created a brand new react application using dotnet core's react templated application using dotnet new react. I then tried to mimic what the Fetch Data Component is doing, and I cannot get my dynamic data to render. I've made sure the component is in the routes component, and that my data is being returned from the server in the format I expect. Here is what I have and what the fetch data component has for code.
FetchData.tsx:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import 'isomorphic-fetch';
interface FetchDataExampleState {
forecasts: WeatherForecast[];
loading: boolean;
}
export class FetchData extends React.Component<RouteComponentProps<{}>, FetchDataExampleState> {
constructor() {
super();
this.state = { forecasts: [], loading: true };
fetch('api/SampleData/WeatherForecasts')
.then(response => response.json() as Promise<WeatherForecast[]>)
.then(data => {
this.setState({ forecasts: data, loading: false });
});
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: FetchData.renderForecastsTable(this.state.forecasts);
return <div>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
{ contents }
</div>;
}
private static renderForecastsTable(forecasts: WeatherForecast[]) {
return <table className='table'>
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
{forecasts.map(forecast =>
<tr key={ forecast.dateFormatted }>
<td>{ forecast.dateFormatted }</td>
<td>{ forecast.temperatureC }</td>
<td>{ forecast.temperatureF }</td>
<td>{ forecast.summary }</td>
</tr>
)}
</tbody>
</table>;
}
}
interface WeatherForecast {
dateFormatted: string;
temperatureC: number;
temperatureF: number;
summary: string;
}
and here is what I have.
Bills.tsx
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
interface BillState {
bills: Bill[],
loading: boolean
}
export class Bills extends React.Component<RouteComponentProps<{}>, BillState>
{
constructor()
{
super();
this.state = { bills: [], loading: true };
fetch("api/SampleData/GetBills")
.then(response => response.json() as Promise<Bill[]>)
.then(data => { this.setState({
bills: data,
loading: false
});
});
}
public render()
{
let contents = this.state.loading
? <p><em>Loading...</em></p>
: Bills.renderBillsToList(this.state.bills);
return <div className="rendered-bills">
<h1>Bills to pay</h1>
{ contents }
</div>
}
public static renderBillsToList(bills: Bill[])
{
return <ul>
{bills.map( (bill, i) => <li key={ i }> { bill.Name } </li>
)}
</ul>;
}
}
interface Bill
{
Name: string;
}
What am I doing wrong in my RenderBillsToTable? I can see the ul and li's rendering, but not my data that I'm certain is being passed.
Apparently the name of the property was 'name' not 'Name'. Looks like this one was a problem between computer and chair.

Categories

Resources