Reputation: 489
I am making a stock portfolio project using Gatsby and a stockmarket API. Currently, when you search by a ticker-symbol it returns the ticker-symbol, market cap, and previous close in a table. When you click on the returned ticker-symbol it brings you to another page. On this next page, I would like to have access to the same API search just to display more details of the stock.
I was told last night here on StackOverflow I could send API data through Link however after looking through some documentation I am not sure how to implement specifically what I described.
I do not mind switching details.js to a class component, I had tried that earlier and setting state up but I just had a plethora of different errors.
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"
export default class index extends React.Component {
state = {
companyName: "",
previousClose: "",
marketCap: "",
change: "",
symbol: "",
topStocks: []
}
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 })
})
}
}
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, query: `yourQuery`}}>{this.state.symbol}</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>
</Layout>
)
}
}
details.js
//import { Link } from "gatsby"
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import Layout from '../components/layout';
const Details = props => {
const [yourState, setYourState] = useState('');
useEffect(() => {
if (props.location.state.someState) {
axios.get(`https://cloud.iexapis.com/stable/stock/XOM/quote?token=******************`)
.then(res => setYourState(res))
}
}, []);
return <Layout>
<div>
</div>
</Layout>;
};
export default Details;
The errors with my current code are:
D:\Web Development\React JS course\gatsby-site\src\pages\details.js
7:5 error React Hook "useEffect" is called in function "details" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks
7:5 error 'useEffect' is not defined no-undef
8:12 error Unexpected use of 'location' no-restricted-globals
9:65 error 'query' is not defined no-undef
✖ 4 problems (4 errors, 0 warnings)
Upvotes: 0
Views: 219
Reputation: 29320
There are a few things, because you have a little weird component/page there.
You are not importing useEffect
in your details.js
page as error shows:
7:5 error 'useEffect' is not defined
Your state passed through <Link>
component needs to be retrieved via props
(or destructuring props
and getting location
directly).
details.js
is a functional component, you don't have a setState
(nor this
) function there. Use useState
hook instead.
query
parameter is never provided to this component. Once you solve the main issues you should pass it via props
.
error 'query' is not defined
Your components are not camelCased.
All errors should fixed with:
//import { Link } from "gatsby"
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import Layout from '../components/layout';
const Details = props => {
const [yourState, setYourState] = useState('');
useEffect(() => {
if (props.location.state.someState) {
axios.get(`https://cloud.iexapis.com/stable/stock/${props.location.state.query}/quote?token=*****************`)
.then(res => setYourState(res))
}
}, []);
return <Layout>
<div>
{/*do stuff with your yourState. (i.e: console.log('hi!', yourState))*/}
</div>
</Layout>;
};
export default Details;
Regarding the second and third points:
const Details= props => {}
equals to const Details= ({ location }) => {}
.
This destructuring saves you one step and get directly location
object instead of doing props.location
in your condition.setState
function is not allowed in functional components rather than class components. It's entirely up to you choosing whether one or another, but you need to be aware of their "limitations" and "benefits". In this case, you need to use useState
hook. As you can see it's composed by const [yourState, setYourState]
. The second element (setYourState
) is the function that will be used to store the value of yourState
, so, your axios asynchronous request will be stored using setYourState
function and retrieved via yourState
. Of course, you can name it whatever you wish.index.js
, update the state and set the query
: <Link to='/details/' state={{setState: this.state.symbol, query: `yourQuery`}}/>
Recommended readings:
If you need a detailed explanation on any point please let me know and I will provide it.
Upvotes: 1