Exercise - Refresh the Prices on Click

Welcome to the thread for the exercise Refresh the prices on Click

Coding exercise: Refresh the price of the coin upon clicking the Refresh button on the line of the coin.

FYI for doing name changes on a variable you can press F2 and VS code will change all the references for you.

App.js - Refresh Prices
  • I moved the API calls into separate functions
  • Call the API instead of calculating a random price change
  • The tricky part was using await Promise.all() as the API call turns the mapping into promises. You get undefined errors in the Coin component without it.
const API_BASE_URL = 'https://api.coinpaprika.com/v1';

  getCoinPrice = (id) => {
    return axios.get(`${API_BASE_URL}/tickers/${id}`);
  }

  handleRefresh = async (valueChangeticker) => {
    // generate the new state by cloning the old state
    // and updating the target coin price
    const responses = this.state.coinData.map(async values => {
      let newValues = { ...values }; // shallow copy
      
      if (values.ticker === valueChangeticker) {
        const response = await this.getCoinPrice(values.key);
        newValues.price = response.data.quotes['USD'].price;
      }

      return newValues;
    });
    const newCoinData = await Promise.all(responses);

    this.setState({ coinData: newCoinData });
  }

1 Like

Coding exercise: Refresh the price of the coin upon clicking the Refresh button on the line of the coin.

I modified the handleRefresh function to get and refresh the price with an api call for a specific coin id. To lift up the id from Coin to App, and as i can’t use key as props, in coinList i passed the id value to the Coin component. Thus Coin has a props.id that it can passed to App when the button is clicked.

App.js
import React from 'react';
import ExchangeHeader from './components/ExchangeHeader/ExchangeHeader';
import CoinList from './components/CoinList/CoinList';
import AccountBalance from './components/AccountBalance/AccountBalance';
import styled from 'styled-components';
import axios from 'axios';


const DivApp = styled.div`
    text-align: center;
    background-color: rgb(20, 56, 97);
    color: #cccccc;
    `;


const COIN_COUNT = 10;
const coinsUrl = 'https://api.coinpaprika.com/v1/coins';
const tickerUrl = 'https://api.coinpaprika.com/v1/tickers/';

class App extends React.Component {
  state = {
    balance: 10000,
    showBalance: true,
    coinData: [ ]
    
  }

  componentDidMount = async () => {
    const response = await axios.get( coinsUrl );
    const coinIds = response.data.slice(0, COIN_COUNT).map( coin => coin.id );

    const promises = coinIds.map( id => axios.get( tickerUrl + id ));
    const coinData = await Promise.all( promises );

    const coinPriceData = coinData.map( function(response) {
      const coin = response.data;
      //debugger;
      return {
        key: coin.id,
        name: coin.name,
        ticker: coin.symbol,
        balance: 0,
        price: parseFloat(Number( coin.quotes["USD"].price ).toFixed(2)) 
      };
    });

    this.setState({ coinData: coinPriceData });
  }


handleRefresh = async (valueChangekey) => {
  const keyData =  await axios.get( tickerUrl + valueChangekey);
  
  const newCoinData = this.state.coinData.map( function( values ) {
    let newValues = {...values};
    if (values.key === valueChangekey) {
      newValues.price = parseFloat(Number( keyData.data.quotes["USD"].price ).toFixed(2));
    };
  
  return newValues;
  });
  this.setState({ coinData: newCoinData });
}


  handleToggleBalance = () => {
    this.setState( function(oldState) {
      return {
        ...oldState,
        showBalance: !oldState.showBalance 
      };
    });
  }

  render() {
    return (
      <DivApp>
        <ExchangeHeader />
        <AccountBalance 
          amount={this.state.balance}
          handleToggleBalance={this.handleToggleBalance} 
          showBalance={this.state.showBalance} />
        <CoinList 
          coinData={this.state.coinData}
          handleRefresh={this.handleRefresh}
          showBalance={this.state.showBalance} />
      </DivApp>
    );
  }
}

export default App;
CoinList.jsx
import React, { Component } from 'react';
import Coin from '../Coins/Coin';
import styled from 'styled-components';


const Table = styled.table`
    margin: 50px auto 50px auto;
    display: inline-block;
    font-size: 1.4rem;
    `;

export default class CoinList extends Component {
    render() {
      /*
        const toggleBalance = this.props.showBalance ?
        <th>Balance</th> : null;
      */

        return (
            <Table> 
            <thead>
              <tr>
                <th>Name</th>
                <th>Ticker</th>
                {this.props.showBalance ? <th>Balance</th> : null}
                <th>Price</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
              {
                this.props.coinData.map( ({key, name, ticker, balance, price}) =>
                  <Coin 
                  key={key} 
                  id={key}
                  name={name} 
                  handleRefresh={this.props.handleRefresh}
                  ticker={ticker}
                  showBalance={this.props.showBalance}
                  balance={balance}
                  price={price} 
                  />
                )
              }
            </tbody>
          </Table>
        )
    }
}```
Coin.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

const Td = styled.td`
    border: 1px solid #cccccc;
    width: 25vh;
`;
const Button = styled.button`
    height: 2rem;
    width: 100%;
    background-color: #282c34;
    color: #61dafb;
    border: none;
    font-size: 1rem;
    :active {
        background: #0053ba;
    }
    :hover {
        border: 1px solid #cccccc;
        border-radius: 3px;
        cursor: pointer;
    }
`;

export default class Coin extends Component {
    handleClick = (event) => {
        // Prevent the default action of submitting the form
        event.preventDefault();
        this.props.handleRefresh(this.props.id);
    }
    render() {
            return(
                <tr>
                  <Td>{this.props.name}</Td>
                  <Td>{this.props.ticker}</Td>
                  {this.props.showBalance ? <Td>{this.props.balance}</Td> : null}
                  <Td>${this.props.price}</Td>
                  <Td>
                      <form action="">
                          <Button onClick={this.handleClick}>Refresh</Button>
                      </form>
                  </Td>
                </tr>
              );
    }
}

Coin.propTypes = {
    name: PropTypes.string.isRequired,
    ticker: PropTypes.string.isRequired,
    price: PropTypes.number.isRequired
}