Created
October 25, 2018 13:47
-
-
Save jmcd/8ea093051da607421b254e82ab26bfca to your computer and use it in GitHub Desktop.
My first react app - an implementation of https://reactjs.org/docs/thinking-in-react.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import './App.css'; | |
class App extends Component { | |
render() { | |
const unfilteredData = [ | |
{ category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football" }, | |
{ category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball" }, | |
{ category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball" }, | |
{ category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch" }, | |
{ category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5" }, | |
{ category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7" } | |
].map(p => { | |
p.rawPrice = parseFloat(p.price.replace('$', '')); | |
return p; | |
}); | |
return ( | |
<FilterableProductTable unfilteredData={unfilteredData} /> | |
); | |
} | |
} | |
export default App; | |
class FilterableProductTable extends Component { | |
constructor(props) { | |
super(props); | |
this.handleTextChange = this.handleTextChange.bind(this); | |
this.handleInStockChange = this.handleInStockChange.bind(this); | |
this.state = { | |
filterText: '', | |
filterInStock: false, | |
}; | |
} | |
handleTextChange(text) { | |
this.setState({ filterText: text }); | |
} | |
handleInStockChange(flag) { | |
this.setState({ filterInStock: flag }); | |
} | |
render() { | |
const unfilteredData = this.props.unfilteredData; | |
const filterText = this.state.filterText.toLocaleLowerCase(); | |
const filterInStock = this.state.filterInStock; | |
const filteredData = unfilteredData.filter(item => | |
item.name.toLocaleLowerCase().includes(filterText) && (!filterInStock || item.stocked === true) | |
); | |
return ( | |
<div> | |
<SearchBar | |
text={this.state.filterText} | |
onTextChange={this.handleTextChange} | |
onInStockChange={this.handleInStockChange} | |
/> | |
<ProductTable data={filteredData} /> | |
</div> | |
); | |
} | |
} | |
class SearchBar extends Component { | |
constructor(props) { | |
super(props); | |
this.handleTextChange = this.handleTextChange.bind(this); | |
this.handleInStockChange = this.handleInStockChange.bind(this); | |
} | |
handleTextChange(e) { | |
const text = e.target.value; | |
this.props.onTextChange(text); | |
} | |
handleInStockChange(e) { | |
this.props.onInStockChange(e.target.checked); | |
} | |
render() { | |
const text = this.props.text; | |
const inStock = this.props.inStock; | |
return ( | |
<div> | |
<div> | |
<input type="text" value={text} onChange={this.handleTextChange} /> | |
</div> | |
<div> | |
<input type="checkbox" value={inStock} onChange={this.handleInStockChange} /><label>Only show products in stock</label> | |
</div> | |
</div> | |
); | |
} | |
} | |
function ProductTable(props) { | |
const productsGroupedByCategory = props.data.reduce(function (acc, item) { | |
(acc[item.category] = acc[item.category] || []).push(item); | |
return acc; | |
}, {}); | |
const productsGroupedByCategoryAndMaxPricesMarked = Object.keys(productsGroupedByCategory).reduce(function (acc, cat) { | |
const products = productsGroupedByCategory[cat]; | |
const maxPrice = Math.max(...products.map(p => p.rawPrice), 0); | |
console.log(maxPrice); | |
const productsInCategory = products.map(p => { | |
return { | |
name: p.name, | |
price: p.price, | |
isMaxPrice: p.rawPrice === maxPrice, | |
}; | |
}); | |
acc[cat] = productsInCategory; | |
return acc; | |
}, {}); | |
return ( | |
<table> | |
<thead> | |
<tr> | |
<th>Name</th> | |
<th>Price</th> | |
</tr> | |
</thead> | |
{ | |
Object.keys(productsGroupedByCategoryAndMaxPricesMarked).map(cat => | |
<tbody key={cat}> | |
<ProductCategoryRow category={cat} /> | |
{productsGroupedByCategoryAndMaxPricesMarked[cat].map(product => <ProductRow key={product.name} product={product} />)} | |
</tbody> | |
) | |
} | |
</table> | |
); | |
} | |
function ProductCategoryRow(props) { | |
const category = props.category; | |
return <tr><th colSpan="2">{category}</th></tr> | |
} | |
function ProductRow(props) { | |
const product = props.product; | |
return ( | |
<tr> | |
{product.isMaxPrice ? <td style={{ color: "red" }}>{product.name}</td> : <td>{product.name}</td>} | |
<td>{product.price}</td> | |
</tr> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment