Welcome to the thread where you can discuss and ask all questions related to the exercise hide the balance
App
- Need to add a state variable for
showBalance
- Pass that state to the sub-components
- Handle the click event to toggle the
showBalance
state
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
balance: 10000,
showBalance: false,
coinData: [ /* etc */]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleToggleShowBalance = this.handleToggleShowBalance.bind(this);
}
handleToggleShowBalance() {
this.setState({showBalance: !this.state.showBalance});
}
render() {
return (
<Content>
<AppHeader />
<AccountBalance amount={this.state.balance}
showBalance={this.state.showBalance}
handleToggleShowBalance={this.handleToggleShowBalance}/>
<CoinList coinData={this.state.coinData}
handleRefresh={this.handleRefresh}
showBalance={this.state.showBalance} />
</Content>
);
}
}
AccountBalance
- Conditionally add the element which displays the balance and insert it using
{ }
- Create a styled component for the button
- Attach the click handler passed down in the props to the
onClick
event of the button
const BtnBalance = styled.button`
font-size: 1.4rem;
margin: 1.5rem 0 1.5rem 5rem;
background-color: rgb(20, 56, 97);
color: #cccccc;
border: 1px solid #cccccc;
border-radius: 7px;
`;
export default class AccountBalance extends Component {
render() {
const buttonText = this.props.showBalance ?
'Hide Balance' : 'Show Balance';
let balance = this.props.showBalance ?
<span>Balance: ${this.props.amount}</span>
: null;
return (
<Section>
{balance}
<BtnBalance onClick={this.props.handleToggleShowBalance}>{buttonText}</BtnBalance>
</Section>
);
}
}
CoinList
- Conditionally add the
<th>
for the balance - Pass the
showBalance
prop state to the child Coin components
export default class CoinList extends Component {
render() {
const balance = this.props.showBalance ?
<th>Balance</th> : null;
return (
<>
<Table>
<thead>
<tr>
<th>Name</th>
<th>Ticker</th>
{balance}
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map(({ name, ticker, balance, price }) =>
<Coin key={ticker}
handleRefresh={this.props.handleRefresh}
name={name}
ticker={ticker}
balance={balance}
showBalance={this.props.showBalance}
price={price} />)
}
</tbody>
</Table>
</>
)
}
}
Coin
- Conditionally display the balance based on the
showBalance
prop - Only the render function changes so omitted the rest of this file
render() {
const balance = this.props.showBalance ?
<Td>{this.props.balance}</Td> : null;
return (
<tr>
<Td>{this.props.name}</Td>
<Td>{this.props.ticker}</Td>
{balance}
<Td>${this.props.price}</Td>
<Td>
<form action="#" method="POST">
<button onClick={this.handleRefresh}>Refresh</button>
</form>
</Td>
</tr>
);
}
Thanks for posting! Noticed I made an error using handleClick on the button instead of handleRefresh. Finally it works!
//App.js
class App extends React.Component {
constructor(props){
super(props);
this.state = {
showBalance:false,
balance: 10000,
coinData: [ …
this.handleRefresh=this.handleRefresh.bind(this);
this.handleShowBalance=this.handleShowBalance.bind(this);
}
handleShowBalance(){
this.setState(
{showBalance:! this.state.showBalance}
);
}
render(){
return (
<AccountBalance amount={this.state.balance}
showBalance={this.state.showBalance }
handleShowBalance={this.handleShowBalance } />
<CoinList coinData={this.state.coinData}
showBalance={this.state.showBalance }
handleRefresh={this.handleRefresh}/>
);
}
//CoinList.jsx
class CoinList extends Component {
render() {
const balanceDisplay= this.props.showBalance ? Balance: ‘’;
return (
{balanceDisplay}
{this.props.coinData.map(({name, ticker,balance, price}) => (
<Coin key={ticker}
showBalance={this.props.showBalance }
handleRefresh={this.props.handleRefresh}
name={name}
ticker={ticker}
balance={balance}
price={price}
/>
))}
Name | Ticker | Price | Action |
---|
);
}
}
// Coins.jsx
render() {
const balanceDisplay= this.props.showBalance ? {this.props.balance}: ‘’;
return(
<tr>
<Td> {this.props.name} </Td>
<Td> {this.props.ticker} </Td>
{balanceDisplay}
<Td>${this.props.price} </Td>
<Td>
<form action='#' method= 'POST'>
<button onClick= {this.handleClick}>refresh</button>
</form>
</Td>
</tr>
) ;
}
//AccountBalance
class AccountBalance extends Component {
render() {
const buttonText= this.props.showBalance ? ‘hide balance’ : ‘show balance’;
const balanceDisplay= this.props.showBalance ? <>Balance: $ {this.props.amount} </> : ‘’;
return (
{balanceDisplay}
{buttonText}
) ;
}
}
Next to your balance, there is a button. Upon pressing this button, hide this balance. Also hide the balance column in the table.
When the balance is hidden, if you press the same button, show both the USD balance as well as the coin balances column.
We use a handleclick function to prevent default behavior of button action in AccountBalance.
We set a show state in App.js and we make passing this state from parent to child as props. The toggling function in App.js manages the show state and it’s passed to the child via props to be triggered by the button
Then, in render functions we use a conditional expression with the show state to display or not the information
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';
const DivApp = styled.div`
text-align: center;
background-color: rgb(20, 56, 97);
color: #cccccc;
`;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
balance: 10000,
coinData: [
{
name: "Bitcoin",
ticker: 'BTC',
balance: 0.5,
price: 9999.9
},
{
name: "Ethereum",
ticker: 'ETH',
balance: 32,
price: 274.9
},
{
name: "Tether",
ticker: 'USDT',
balance: 0,
price: 1
},
{
name: "Ripple",
ticker: 'XRP',
balance: 1000,
price: 0.2
},
{
name: "Bitcoin Cash",
ticker: 'BCH',
balance: 0,
price: 298.99
},
{
name: "Bthereum",
ticker: 'BTH',
balance: 0.5,
price: 274.9
},
{
name: "Cthereum",
ticker: 'CTH',
balance: 0.5,
price: 274.9
}
],
showBalance: true
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleToggleBalance = this.handleToggleBalance.bind(this);
}
handleRefresh(valueChangeticker) {
//const coin = this.state.coinData.find(({ticker}) => ticker === valueChangeticker);
const newCoinData = this.state.coinData.map(function ({ ticker, name, price }) {
let newPrice = price;
if (ticker === valueChangeticker) {
const randomPercentage = 0.995 + Math.random() * 0.01;
newPrice = newPrice * randomPercentage;
};
return {
ticker,
name,
price: newPrice
}
});
this.setState({ coinData: newCoinData });
}
handleToggleBalance() {
this.setState({ showBalance: !this.state.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;
AccountBalance.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
const Section = styled.section`
/*border: 1px solid red;*/
margin: 20px auto 0 auto;
padding-left: 1.5 rem 0 1.5rem 5rem;
width: 98vw;
max-width: 780px;
font-size: 2rem;
text-align: left;
`;
const Button = styled.button`
margin: 10px auto 0 auto;
float: right;
border: none;
background-color: #282c34;
color: #61dafb;
font-size: 1.4rem;
:active {
background: #0053ba;
}
:hover {
border: 1px solid #cccccc;
border-radius: 3px;
cursor: pointer;
}
`;
export default class AccountBalance extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
// Prevent the default action of submitting the form
event.preventDefault();
this.props.handleToggleBalance();
}
render() {
const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
const toggleBalance = this.props.showBalance ?
<span><strong>Balance : </strong>$ {this.props.amount}</span> : null;
return (
<Section className="balance">
{toggleBalance}
<Button onClick={this.handleClick}>{buttonText}</Button>
</Section>
);
}
}
AccountBalance.propTypes = {
amount: PropTypes.number.isRequired
}
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>
{toggleBalance}
<th>Price</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map( ({name, ticker, balance, price}) =>
<Coin key={ticker} 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 './Coin.css';
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 {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
// Prevent the default action of submitting the form
event.preventDefault();
this.props.handleRefresh(this.props.ticker);
}
render() {
const toggleBalance = this.props.showBalance ?
<Td>{this.props.balance}</Td> : null;
return(
<tr>
<Td>{this.props.name}</Td>
<Td>{this.props.ticker}</Td>
{toggleBalance}
<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
}
AccountBalance
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components';
const Section = styled.section`
font-size: 2rem;
text-align: left;
padding: 1.5rem 0 1.5rem 5rem;
`;
export default class AccountBalance extends Component {
render() {
let showBal = this.props.showBalance ? <>AccountBalance: ${this.props.amount}</> : '';
const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
return (
<Section>
{ showBal }
< button onClick={this.props.handleBalance} >{buttonText}</button>
</Section>
);
}
}
AccountBalance.propTypes = {
amount: PropTypes.number.isRequired
}
Coin
render() {
const balance = this.props.showBalance ? <><CoinRow>{this.props.balance}</CoinRow></> : '';
return (
<tr>
<CoinRow>{this.props.name}</CoinRow>
<CoinRow>{this.props.ticker}</CoinRow>
{ balance }
<CoinRow>${this.props.price}</CoinRow>
<CoinRow> <form action="#" method="POST" >
<button onClick={this.handleClick}>Refresh</button>
</form>
</CoinRow>
</tr>
);
}
}
CoinList
import React, { Component } from 'react'
import Coin from '../Coin/Coin';
import styled from 'styled-components';
const Table = styled.table`
margin: 50px auto 50 px auto;
display: inline-block;
font-size: 1.4rem;
`;
export default class CoinList extends Component {
render() {
let balance = this.props.showBalance ? <th>Balance</th> : '';
return (
<Table>
<thead>
<tr>
<th>Name</th>
<th>Ticker</th>
{ balance }
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map( ({name, ticker, balance, price}) =>
<Coin key={ticker} handleRefresh={this.props.handleRefresh}
name={name}
ticker={ticker}
showBalance={this.props.showBalance}
balance={balance}
price={price} />
)
}
</tbody>
</Table>
)
}
}
App
class App extends React.Component {
constructor(props){
super(props);
this.state = {
balance: 10000,
showBalance: false,
coinData: [
//extraneous
]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleBalance = this.handleBalance.bind(this);
}
handleRefresh(valueChangeTicker) {
const newCoinData = this.state.coinData.map( function( {ticker, name, price}) {
let newPrice = price;
if( valueChangeTicker === ticker) {
const randomPercentage = 0.995 + Math.random() * .01;
newPrice = newPrice * randomPercentage;
}
return {
ticker,
name,
price: newPrice
}
});
this.setState({ coinData: newCoinData });
}
handleBalance() {
this.setState({
showBalance: !this.state.showBalance
});
}
render() {
return (
<Div>
<ExchangeHeader />
<AccountBalance
amount={this.state.balance}
showBalance={this.state.showBalance}
handleBalance={this.handleBalance}
/>
<CoinList
coinData={this.state.coinData}
handleRefresh={this.handleRefresh}
showBalance={this.state.showBalance}/>
</Div>
);
}
}
export default App;
I learned as much from the cheat codes and rubbernecking classmate’s solutions as I did from the lecture. Anyway I think it’s all working now…per my manual testing. I see hints of automated React testing frameworks in the template…?
Good job with the solution!
I’d recommend sharing either your GitHub, or doing the coding in codesandbox.io and just sharing the link.
Yes, create-react-app includes testing set up. We didn’t cover it in the course, but automated testing (unit test, integration test, acceptance test) are important parts of software engineering. Here, you’d be able to write unit tests and integration tests between your components.
App.js
import React from 'react';
import './App.css';
import CoinList from './components/CoinList';
import AccountBalance from "./components/AccountBalance";
import CoinHeader from './components/CoinHeader';
import styled from "styled-components";
const Div = styled.div`
text-align: center;
background-color: rgb(20,56,97);
color: #cccccc;
`;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
balance: 1000,
showBalance: true,
coinData: [
{
name: "Bitcoin",
ticker: "BTC",
balance: 0.5,
price: 9999.99
},
{
name: "Ethereum",
ticker: "ETH",
balance: 32,
price: 299.99
},
{
name: "Tether",
ticker: "USDT",
balance: 19,
price: 1.0
},
{
name: "Ripple",
ticker: "XRP",
balance: 3,
price: 0.2
},
{
name: "Bitcoin Cash",
ticker: "BCH",
balance: 0,
price: 299.99
}
]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleRefreshShowBalance = this.handleRefreshShowBalance.bind(this);
}
handleRefresh(valueChangedTicker) {
const newCoinData = this.state.coinData.map(({name, ticker, balance, price}) => {
let newPrice = price;
if (valueChangedTicker === ticker) {
const randomPercentage = 0.995 + Math.random() * 0.01;
newPrice = newPrice * randomPercentage;
}
return {name, ticker, balance, price: newPrice}
});
this.setState({coinData:newCoinData});
}
handleRefreshShowBalance(valueChangedShowBalance) {
this.setState({showBalance:valueChangedShowBalance});
}
render() {
return (
<Div>
<CoinHeader />
<AccountBalance
amount={this.state.balance}
handleRefreshShowBalance={this.handleRefreshShowBalance}
showBalance={this.state.showBalance} />
<CoinList
coinData={this.state.coinData}
handleRefresh={this.handleRefresh}
showBalance={this.state.showBalance} />
</Div>
);
}
}
export default App;
AccountBalance.jsx
import React, {Component} from "react";
import PropTypes from 'prop-types';
import styled from "styled-components";
const Section = styled.section`
border: 1px solid red;
font-size: 2rem;
text-align: center;
passing: 1.5rem 0 1.5rem 5rem;
`;
export default class AccountBalance extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
event.preventDefault();
this.props.handleRefreshShowBalance(!this.props.showBalance);
}
render() {
const buttonText = this.props.showBalance ? "Hide Balance" : "Show Balance";
const balanceText = this.props.showBalance ? `Balance: $${this.props.amount}` : "";
return (
<Section>
{balanceText}
<button onClick={this.handleClick}>{buttonText}</button>
</Section>
);
}
}
AccountBalance.propTypes = {
amount: PropTypes.number.isRequired
}
CoinList.jsx
import React from 'react';
import Coin from './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 React.Component {
render() {
let balanceHeader = this.props.showBalance ? <th>Balance</th> : null;
return (
<Table>
<thead>
<tr>
<th>Name</th>
<th>Ticker</th>
<th>Price</th>
{balanceHeader}
<th>Action</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map( ({name, ticker, balance, price}) =>
<Coin
key={ticker}
handleRefresh={this.props.handleRefresh}
showBalance={this.props.showBalance}
name={name}
ticker={ticker}
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 TdHidden = styled.td`
border: 1px solid #cccccc;
width: 25vh;
display:none;
`;
export default class Coin extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
event.preventDefault();
this.props.handleRefresh(this.props.ticker);
}
render() {
let balanceCell = this.props.showBalance ? <Td>${this.props.balance}</Td> : <TdHidden>${this.props.balance}</TdHidden>;
return (
<tr>
<Td>{this.props.name}</Td>
<Td>{this.props.ticker}</Td>
<Td>${this.props.price}</Td>
{balanceCell}
<Td>
<form action="#" method="POST">
<button onClick={this.handleClick}>Refresh</button>
</form>
</Td>
</tr>
);
}
}
Coin.propTypes = {
name: PropTypes.string.isRequired,
ticker: PropTypes.string.isRequired,
price: PropTypes.number.isRequired
}
used this code in the render()
// render function with a styled component depending on the showBlance flag
// show the balance or not.
render() {
const buttonText = this.props.showBalance ? ‘Hide Balance’ : ‘Show Balance’;
if (this.props.showBalance) {
return (
Balance: ${this.getAmount()}
{buttonText}
);
} else {
return (
{buttonText}
)
}
}
render() {
if ( this.props.showBalance ) {
return (
{this.props.name}
{this.props.ticker}
${this.getPrice()}
{this.props.balance}
Refresh
)
} else {
return (
{this.props.name}
{this.props.ticker}
${this.getPrice()}
Refresh
)
}
}
and
I’ve deliberately missed out some of the details to shorten the code. Just included the bits that had changes in. I struggled with this and had to get some pointers from previous posts here to get started, but got my head around it as I went through.
App
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
balance: 10000,
showBalance: false,
coinData: [etc]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleToggleBalance = this.handleToggleBalance.bind(this);
}
handleRefresh(valueChangeTicker) {
const newCoinData = this.state.coinData.map( function( {ticker, name, price} ) {
let newPrice = price;
if (valueChangeTicker === ticker) {
const randomPercentage = 0.995 + Math.random() * 0.01;
newPrice = newPrice * randomPercentage;
}
return {
ticker,
name,
price: newPrice
}
});
this.setState({ coinData: newCoinData });
}
handleToggleBalance() {
this.setState({showBalance: ! this.state.showBalance});
}
render() {
return (
<Div>
<Header/>
<AccountBalance amount= {this.state.balance} showBalance={this.state.showBalance}
handleToggleBalance = {this.handleToggleBalance} />
<CoinList coinData={this.state.coinData} handleRefresh={this.handleRefresh}
showBalance = {this.state.showBalance} />
</Div>
);
}
}
AccountBalance
export default class AccountBalance extends Component {
render() {
const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
let balanceToggle = this.props.showBalance ? <> Balance: ${this.props.amount} </> : null;
return (
<Section>
{balanceToggle}
<button onClick={this.props.handleToggleBalance}>{buttonText}</button>
</Section>
);
}
}
AccountBalance.propTypes = {
amount: PropTypes.number.isRequired
}
CoinList
export default class CoinList extends Component {
render() {
let balanceToggle = this.props.showBalance ? <th> Balance </th> : null;
return (
<Table>
<thead>
<tr>
<th>Name</th>
<th>Ticker</th>
<th>Price</th>
{balanceToggle}
<th>Action</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map ( ({name, ticker, price, balance}) =>
<Coin key= {ticker}
handleRefresh={this.props.handleRefresh}
showBalance = {this.props.showBalance}
name={name}
ticker={ticker}
balance= {balance}
price={price} />
)
}
</tbody>
</Table>
)
}
}
Coin
render() {
let balanceToggle = this.props.showBalance ? <Td> {this.props.balance} </Td> : null;
return (
<tr>
<Td>{this.props.name}</Td>
<Td>{this.props.ticker}</Td>
<Td>${this.props.price}</Td>
{balanceToggle}
<Td>
<form action="#" method="POST">
<button onClick={this.handleClick}>Refresh</button>
</form>
</Td>
</tr>
)
}
}
Coin.propTypes = {
name: PropTypes.string.isRequired,
ticker: PropTypes.string.isRequired,
price: PropTypes.number.isRequired
}
It was a challenging task, but now the lecture is more clear Looking forward to the next one.
App
class App extends React.Component {
constructor(props){
super(props);
this.state = {
balance: 10000,
showBalance: true,
coinData: [
{/*----- snip -----*/
}
]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleVisibilityChange = this.handleVisibilityChange.bind(this);
}
handleVisibilityChange(){
this.setState( function(oldState) {
return{
...oldState,
showBalance: !oldState.showBalance
}
});
}
handleRefresh(valueChangeTicker) {
const newCoinData = this.state.coinData.map( function( {ticker, name, price, balance} ) {
let newPrice = price;
if( valueChangeTicker === ticker) {
const randomPercentage = 0.995 + Math.random() * 0.01;
newPrice = newPrice * randomPercentage;
}
return{
ticker,
name,
balance,
price: newPrice }
});
this.setState({ coinData: newCoinData});
}
render() {
return (
<StyledDiv>
<AppHeader/>
<AccountBalance amount={this.state.balance}
showBalance={this.state.showBalance}
handleVisibilityChange={this.handleVisibilityChange}/>
<CoinList coinData={this.state.coinData}
showBalance = {this.state.showBalance}
handleRefresh={this.handleRefresh}/>
</StyledDiv>
);
}
}
CoinList
export default class CoinList extends Component {
render() {
return (
<table className="coin-table">
<thead>
<tr>
<th>Name</th>
<th>Ticker</th>
<th>Price</th>
{this.props.showBalance ? <th>Balance</th> : null}
<th>Action</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map( ({name, ticker, price, balance}) =>
<Coin key={ticker}
handleRefresh={this.props.handleRefresh}
name={name}
ticker = {ticker}
price={price}
showBalance={this.props.showBalance}
balance={balance}
/>
)
}
</tbody>
</table>
)
}
}
Coin
export default class Coin extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this)
}
handleClick(event){
event.preventDefault();
this.props.handleRefresh(this.props.ticker)
}
render() {
return (
<tr>
<TableData>{this.props.name}</TableData>
<TableData>{this.props.ticker}</TableData>
<TableData>${this.props.price}</TableData>
{this.props.showBalance ? <TableData>{this.props.balance}</TableData> : null}
<TableData>
<form action="#" >
<button onClick={this.handleClick}>Refresh</button>
</form>
</TableData>
</tr>
);
}
}
AccountBalance
export default class AccountBalance extends Component {
render() {
const buttonText = this.props.showBalance ? 'Hide balance': 'Show balance';
let content = null;
if ( this.props.showBalance ) {
content = <>Balance: $ {this.props.amount}</>
}
return (
<Section>
{content}
<button onClick={this.props.handleVisibilityChange}>{buttonText}</button>
</Section>
)
}
}
There’s way too many screenshots and not sure how to organise them cleanly so instead I’ll put my github repo here for you to review:
https://github.com/CatalystJesal/coin-exchange/tree/master/src/components
The one thing I wanted to do is to make the button not move to take the position of the hidden text balance when I hide it. I tried different CSS but I failed at doing that, I’m really not that good when it comes to positioning elements the way I would like them. I spent more time on trying to position my balance button than showing/hiding balances part of the exercise.
EDIT
I updated my code on github as I realised you decided to hide the column entirely and the balance header for both the account balance and coin balance column, so now I’ve done the same. I use to have it where “Balance:” part stayed and the column of coin balances remained but only the values would clear from the column.
As a developer, you will work implementing designs of other people. I also suggest researching a bit of CSS layouting (Flexbox, Grid), because this course is not meant to teach you web styling, and it’s hard to know what you don’t yet know if no-one told you it’s experience with flexbox and grid is what you need rather than position: absolute, relative or inline-block display mode etc.
In AccountBalance.jsx:
render() {
const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
if (this.props.showBalance === true) {
return (
<Section>
Balance: $ {this.props.amount}
<button onClick = {this.props.handleToggle}>{buttonText}</button>
</Section>
);
}
else {
return (
<Section>
<button onClick = {this.props.handleToggle}>{buttonText}</button>
</Section>
);
}
}
In CoinList.jsx:
<tbody>
{
this.props.coinData.map( ({name, ticker, price, balance}) =>
<Coin key={ticker}
handleRefresh={this.props.handleRefresh}
name={name}
ticker={ticker}
price={price}
balance={balance}
showBalance={this.props.showBalance} />
)
}
</tbody>
In Coin.jsx:
render() {
if (this.props.showBalance === true) {
return (
<tr>
<CoinRow>{this.props.name}</CoinRow>
<CoinRow>{this.props.ticker}</CoinRow>
<CoinRow>${this.props.price}</CoinRow>
<CoinRow>{this.props.balance}</CoinRow>
<CoinRow>
<form action="#" method="POST">
<Button onClick = {this.handleClick}>Refresh</Button>
</form>
</CoinRow>
</tr>
);
}
else {
return (
<tr>
<CoinRow>{this.props.name}</CoinRow>
<CoinRow>{this.props.ticker}</CoinRow>
<CoinRow>${this.props.price}</CoinRow>
<CoinRow></CoinRow>
<CoinRow>
<form action="#" method="POST">
<Button onClick = {this.handleClick}>Refresh</Button>
</form>
</CoinRow>
</tr>
);
}
}
}
Coin.propTypes = {
name: PropTypes.string.isRequired,
ticker: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
balance: PropTypes.number.isRequired
}
In App.js:
this.state = {
balance: 10000,
showBalance: true,
coinData: [ ... ]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleToggle = this.handleToggle.bind(this)
handleToggle() {
if (this.state.showBalance === true) {
this.setState ({
showBalance: false
});
}
else {
this.setState ({
showBalance: true
});
}
}
render() {
return (
<Div>
<ExchangeHeader />
<AccountBalance amount={this.state.balance} showBalance={this.state.showBalance} handleToggle={this.handleToggle}/>
<CoinList coinData={this.state.coinData} showBalance={this.state.showBalance} handleRefresh={this.handleRefresh} />
</Div>
);
}
I have a lot of code written twice because of the if & else statements. There probably is a shorter way.
Goal: Implement functionality to toggle the main and the individual coin balances.
Listed are only changes necessary for this update with comments in the code:
App.js
...
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
balance: 10000,
showBalance: false, //added bool so condition can be passed on
coinData: [...]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleBalanceDisplay = this.handleBalanceDisplay.bind(this);
//add binding
}
handleBalanceDisplay() {
this.setState({showBalance: !this.state.showBalance});//switch bool
}
handleRefresh(valueChangeTicker) {...}
render() {
return (
<Div className="App">
<ExchangeHeader/>
<AccountBalance amount={this.state.balance}
showBalance={this.state.showBalance} //added prop
handleBalanceDisplay={this.handleBalanceDisplay}/>
//added prop
<CoinList coinData={this.state.coinData}
showBalance={this.state.showBalance}
handleRefresh={this.handleRefresh}/>
</Div>
);
}
}
...
AccountBalance.jsx
...
const Button = styled.button`
font-size: 1.6rem;
margin: 1.5rem 0 1.5rem 5rem;
background-color: #282c34;
color: #fff;
border: 1px solid #fff;
border-radius: 5px;
`; //styled button
export default class AccountBalance extends Component {
render() {
const buttonText = this.props.showBalance ?
'Hide Balance' : 'Show Balance';
//conditional display of button text
let balance = this.props.showBalance ?
<span>Account Balance: ${this.props.amount}</span> : null;
//conditional display of balance
return (
<Section>
{balance}
<Button onClick={this.props.handleBalanceDisplay}>
{buttonText}
</Button>
</Section>
);//replace elements with objects
}
}
...
CoinList.jsx
...
export default class CoinList extends Component {
render() {
const coinBalance = this.props.showBalance ?
<th>Balance</th> : null;
//make display of table header conditional
return (
<Table>
<thead>
<tr>
<th>Name</th>
<th>Ticker</th>
<th>Price</th>
{coinBalance}
<th>Actions</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map(({name, ticker, price, balance}) =>
<Coin key={ticker}
handleRefresh={this.props.handleRefresh}
name={name}
ticker={ticker}
showBalance={this.props.showBalance}
balance={balance}
price={price}/>
)
}
</tbody>
</Table>
)
}// replace elements with conditional objects
}
Coin.jsx
...
const Button = styled.button`
font-size: 1.0rem;
margin: 0.5rem 0 0.5rem 0;
background-color: #282c34;
color: #fff;
border: 1px solid #fff;
border-radius: 5px;
`;//styled buttons
export default class Coin extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
event.preventDefault();
this.props.handleRefresh(this.props.ticker);
}
render() {
const coinBalance = this.props.showBalance ?
<Td>{this.props.balance} {this.props.ticker}</Td> : null;
//conditional display of the coin balance
return (
<tr>
<Td>{this.props.name}</Td>
<Td>{this.props.ticker}</Td>
<Td>${this.props.price}</Td>
{coinBalance}
<Td>
<form action='#' method='POST'>
<Button onClick={this.handleClick}>Refresh
</Button>
</form>
</Td>
</tr>
);//replace elements with conditional objects
}
}
...
AppJs- Changes-
Add new state variable showBalance
this.state = {
showBalance : true,
}
handleBalanceDisplay(showBalanceFlag) {
let hideBalance = false;
hideBalance = showBalanceFlag ? false : true;
this.setState({
showBalance : hideBalance
});
}
render() {
return (
);
}
AccountBalance:-
hideBalance() {
this.props.handleBalanceDisplay(this.props.showBalance)
}
Coin.JSX-New CoinRow
${this.props.balance}
CoinList.jsx - new property ‘showBalance’
)
}
App.js
this.state = {
balance: 10000,
showBalance: true,
....
this.toggleBalance = this.toggleBalance.bind(this);
....
toggleBalance(changeShowBalance) {
this.setState({ showBalance: !changeShowBalance });
}
handleRefresh(valueChangeTicker) {
const newCoinData = this.state.coinData.map( ({ticker, name, price, balance}) => {
let newPrice = price;
if(valueChangeTicker === ticker) {
const randomPercentage = 0.995 + Math.random() * 0.01;
newPrice = newPrice * randomPercentage;
}
return {
ticker,
name,
price: newPrice,
balance,
};
});
this.setState({ coinData: newCoinData });
}
.....
<AccountBalance amount={this.state.balance} showBalance={this.state.showBalance} toggleBalance={this.toggleBalance} />
<CoinList coinData={this.state.coinData} showBalance={this.state.showBalance} handleRefresh={this.handleRefresh} />
AccountBalance.jsx
this.handleBalance = this.handleBalance.bind(this);
...
handleBalance(event) {
event.preventDefault();
this.props.toggleBalance(this.props.showBalance);
}
...
export default class AccountBalance extends Component {
constructor(props) {
super(props);
this.handleBalance = this.handleBalance.bind(this);
}
handleBalance(event) {
event.preventDefault();
this.props.toggleBalance(this.props.showBalance);
}
render() {
const buttonText = this.props.showBalance ? "Hide Balance" : "Show Balance";
const Balance = styled.span`
border: 1px solid cyan;
display: ${ this.props.showBalance ? "block" : "none" };
`;
return (
<Section>
<Balance showBalance={this.props.showBalance}>Balance: ${this.props.amount}</Balance>
<form action="#" method="POST">
<button onClick={this.handleBalance}>{buttonText}</button>
</form>
</Section>
);
}
}
Coin.jsx
this.handleClick = this.handleClick.bind(this);
...
const CoinBalanceRow = styled.td`
border: 1px solid #cccccc;
width: 35vh;
display: ${ this.props.showBalance ? "block" : "none" };
`;
...
<CoinBalanceRow showBalance={this.props.showBalance}>{this.props.balance}</CoinBalanceRow>
CoinList.jsx
const CoinBalanceTH = styled.td`
width: 35vh;
display: ${ this.props.showBalance ? "block" : "none" };
`;
...
<CoinBalanceTH>Balance</CoinBalanceTH>
...
{
this.props.coinData.map( ({name, ticker, price, balance}) =>
<Coin key={ticker}
handleRefresh={this.props.handleRefresh}
showBalance={this.props.showBalance}
name={name}
ticker={ticker}
balance={balance}
price={price} />
)
}
I abbreviated the code in my dropdowns to show the code necessary for the Exercise - Hide the Balance.
App.js
Added showBalance to centralize state
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showBalance: true,
balance: 10000,
coinData: [
{
name: 'Bitcoin',
ticker: 'BTC',
balance: 0.5,
price: 9999.99
},
...
Added binding and setState
]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleToggleShowBalance = this.handleToggleShowBalance.bind(this);
}
handleToggleShowBalance() {
this.setState({showBalance: ! this.state.showBalance});
}
...
Render showBalance from state.
render() {
return (
<AppDiv>
<AppHeader />
<AccountBalance
amount={this.state.balance}
showBalance={this.state.showBalance}
handleToggleShowBalance={this.handleToggleShowBalance} />
<CoinList
coinData={this.state.coinData}
showBalance={this.state.showBalance}
handleRefresh={this.handleRefresh} />
</AppDiv>
);
}
...
AccountBalance.jsx
Added event handler to button to toggle show balance
Added showBalance prop to showAccountBalance!
...
export default class AccountBalance extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event){
event.preventDefault();
this.props.handleToggleShowBalance();
}
render() {
const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
const showAccountBalance = this.props.showBalance ? <span>Balance: ${this.props.amount} </span> : null;
return (
<Section>
{showAccountBalance}
<button onClick={this.handleClick} >{buttonText}</button>
</Section>
);
}
}
...
Coin.jsx
Added showBalance prop as coinBalance
render() {
let coinBalance = this.props.showBalance ? <Td>{this.props.balance}</Td> : null;
return (
<tr>
<Td>{this.props.name}</Td>
<Td>{this.props.ticker}</Td>
<Td>${this.props.price}</Td>
{coinBalance}
<Td>
<form action="#" method="POST">
<button onClick={this.handleClick}>Refresh</button>
</form>
</Td>
</tr>
);
}
}
Coin.propTypes = {
name: PropTypes.string.isRequired,
ticker: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
balance: PropTypes.number.isRequired
}
CoinList.jsx
Added showBalance prop as coinBalance.
Passed showBalance prop to Coin
...
export default class CoinList extends Component {
render() {
let coinBalance = this.props.showBalance ? <th>Balance</th> : null;
return (
<Table>
<thead>
<tr>
<th>Name</th>
<th>Ticker</th>
<th>Price</th>
{coinBalance}
<th>Actions</th>
</tr>
</thead>
<tbody>
{
this.props.coinData.map( ({name,ticker,price,balance}) =>
<Coin key={ticker}
handleRefresh={this.props.handleRefresh}
name={name}
ticker={ticker}
showBalance={this.props.showBalance}
balance={balance}
price={price} />
)
}
</tbody>
</Table>
);
}
}
Show Balance
Hide Balance