React Native - Stock API

This lesson is part of a series on React Native.

Step 14 Stock API calls

Make sure you've gone through the alpha-vantage-samples.html sample code before starting this.

Create an .env file (if you dont' already have one) in the project root folder (this file will be ignored from the repo - look at the .gitignore file) Add your API key like so:

EXPO_PUBLIC_ALPHA_VANTAGE_API_KEY="PUT YOUR KEY HERE"

Note: remember to prefix your env variable name with EXPO_PUBLIC_

Install Axios (if you have not yet installed it for the project):

npm install axios

Create an api folder in the project root (if you have not already created it)

Create a file named stock-api.js file into the api folder and add this code to the file:

import axios from "axios";

const BASE_URL="https://www.alphavantage.co/query";

export async function getQuote(symbol) {
  try {
    const response = await axios.get(BASE_URL, {
      params: {
        function: "GLOBAL_QUOTE",
        symbol: symbol,
        apikey: process.env.EXPO_PUBLIC_ALPHA_VANTAGE_API_KEY
      }
    });
    //console.log(response.data)
    return response.data["Global Quote"];
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}

Update nyse.jsx to look like this:

import { StyleSheet, Text, View } from 'react-native'
import {useState} from 'react'
import {getQuote} from '../../api/stock-api'
import { TextInput } from 'react-native-web'
import CustomButton from '../../components/CustomButton'
import CustomScreen from '../../components/CustomScreen'
import CustomText from '../../components/CustomText'

const nyse = () => {
  const [symbol, setSymbol] = useState('')
  const [quote, setQuote] = useState(null)

  const handleGetQuote = async () => {
    if (!symbol) return
      const response = await getQuote(symbol)
      setQuote(response)
  }

  return (
    <CustomScreen>
      {quote && (
        <View>
          <CustomText title>Symbol: {quote["01. symbol"]}</CustomText>
          <CustomText>Open: {quote["02. open"]}</CustomText>
          <CustomText>High: {quote["03. high"]}</CustomText>
          <CustomText>Low: {quote["04. low"]}</CustomText>
          <CustomText>Close: {quote["05. price"]}</CustomText>
        </View>
      )}
      <TextInput
        placeholder="Enter stock symbol"
        onChange={(e) => setSymbol(e.target.value)}
        style={styles.input}
      />
      <CustomButton onPress={handleGetQuote}>
        <Text style={{color: 'white', textAlign: 'center', fontWeight: 'bold'}} >
          Get Quote
        </Text>
      </CustomButton>
      
      {/* {quote && (<Text>{JSON.stringify(quote)}</Text>)} */}

    </CustomScreen>
  )
}

export default nyse

const styles = StyleSheet.create({
  input:{
    height: 40,
    margin: 12,
    borderWidth: 1,
    padding: 10,
  }
})

Caching Responses

Now let's incorporate a list so we can 'cache' the quotes that we've already made API calls for.

Update nyse.jsx to look like this:

import { Pressable, StyleSheet, Text, View } from 'react-native'   ///// Add import for pressable
import {useState} from 'react'
import {getQuote} from '../../api/stock-api'
import { TextInput } from 'react-native-web'
import CustomButton from '../../components/CustomButton'
import CustomScreen from '../../components/CustomScreen'
import CustomText from '../../components/CustomText'
import Spacer from '../../components/Spacer'  //// Add import for Pressable

const nyse = () => {
  const [symbol, setSymbol] = useState('')
  const [quote, setQuote] = useState(null)
  const [quoteList, setQuoteList] = useState([]) //////////////// Add this


  const handleGetQuote = async () => {  ////////////////// update this function
    if (!symbol) return

    // check to see if we already have this symbol in quoteList
    const cachedSymbol = quoteList.find(q => q["01. symbol"] === symbol)
    
    if(cachedSymbol) {
      setQuote(cachedSymbol)
      return
    }else{
      const response = await getQuote(symbol)
      setQuote(response)
      setQuoteList([...quoteList, response])
    }
  }

  return (
    <CustomScreen>
      {quote && (
        <View>
          <CustomText title>Symbol: {quote["01. symbol"]}</CustomText>
          <CustomText>Open: {quote["02. open"]}</CustomText>
          <CustomText>High: {quote["03. high"]}</CustomText>
          <CustomText>Low: {quote["04. low"]}</CustomText>
          <CustomText>Close: {quote["05. price"]}</CustomText>
        </View>
      )}
      <TextInput
        placeholder="Enter stock symbol"
        onChange={(e) => setSymbol(e.target.value)}
        style={styles.input}
      />
      <CustomButton onPress={handleGetQuote}>
        <Text style={{color: 'white', textAlign: 'center', fontWeight: 'bold'}} >
          Get Quote
        </Text>
      </CustomButton>
      
      {/* {quote && (<Text>{JSON.stringify(quote)}</Text>)} */} 

      //////////////////////////////////////////////////////////////// Add this to the jsx:
      <Spacer height={25} />
      {quoteList.length > 0 && (
        <View>
          <Text>Quote History:</Text>
          {quoteList.map((q, index) => (
            <View key={index}>
              <Pressable onPress={() => setQuote(q)}>
                <CustomText title>
                  {q["01. symbol"]}
                </CustomText>
              </Pressable>
            </View>
          ))}
        </View>
      )}


    </CustomScreen>
  )
}

export default nyse

const styles = StyleSheet.create({
  input:{
    height: 40,
    margin: 12,
    borderWidth: 1,
    padding: 10,
  },
  //////////////////////// add this
  listItem:{
    fontSize: 16,
    padding: 5,
  }
})