Caleb
Caleb

Reputation: 489

Sending API data using Link in Gatsby

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

Answers (1)

Ferran Buireu
Ferran Buireu

Reputation: 29320

There are a few things, because you have a little weird component/page there.

  1. You are not importing useEffect in your details.js page as error shows:

    7:5 error 'useEffect' is not defined

  2. Your state passed through <Link> component needs to be retrieved via props (or destructuring props and getting location directly).

  3. details.js is a functional component, you don't have a setState (nor this) function there. Use useState hook instead.

  4. 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

  5. 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:

  1. 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.
  2. Your 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.
  3. From your 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

Related Questions