|
const PRODUCTS = [ |
|
{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'} |
|
]; |
|
|
|
// 搜索条 |
|
class SearchBar extends React.Component { |
|
constructor(props) { |
|
super(props); |
|
this.handleFilterTextChange = this.handleFilterTextChange.bind(this); |
|
this.handleInStockChange = this.handleInStockChange.bind(this); |
|
} |
|
|
|
handleFilterTextChange(e) { |
|
this.props.onFilterTextChange(e.target.value); |
|
} |
|
|
|
handleInStockChange(e) { |
|
this.props.onInStockChange(e.target.checked); |
|
} |
|
|
|
render() { |
|
const filterText = this.props.filterText; |
|
const inStockOnly = this.props.inStockOnly; |
|
return ( |
|
<form> |
|
<input type="text" placeholder="Search..." value={filterText} onChange={this.handleFilterTextChange}/> |
|
<p> |
|
<input type="checkbox" checked={inStockOnly} onChange={this.handleInStockChange}/> |
|
|
|
Only show products in stock |
|
</p> |
|
</form> |
|
); |
|
} |
|
} |
|
|
|
// 产品列表 |
|
class ProductTable extends React.Component { |
|
render() { |
|
const filterText = this.props.filterText; |
|
const inStockOnly = this.props.inStockOnly; |
|
|
|
const rows = []; |
|
let lastCategory = null; |
|
this.props.products.forEach((product) => { |
|
if (product.name.indexOf(filterText) === -1) { |
|
return; |
|
} |
|
if (inStockOnly && !product.stocked) { |
|
return; |
|
} |
|
if (product.category !== lastCategory) { |
|
// 添加分类 |
|
rows.push(<ProductCategoryRow category={product.category} key={product.category}/>); |
|
} |
|
// 添加商品 |
|
rows.push(<ProductRow product={product} key={product.name}/>); |
|
lastCategory = product.category; |
|
}); |
|
|
|
return ( |
|
<table> |
|
<thead> |
|
<tr> |
|
<th>Name</th> |
|
<th>Price</th> |
|
</tr> |
|
</thead> |
|
<tbody>{rows}</tbody> |
|
</table> |
|
); |
|
} |
|
} |
|
|
|
class ProductCategoryRow extends React.Component { |
|
render() { |
|
const category = this.props.category; |
|
return ( |
|
<tr> |
|
<th colspan="2">{category}</th> |
|
</tr> |
|
); |
|
} |
|
} |
|
|
|
class ProductRow extends React.Component { |
|
render() { |
|
const product = this.props.product; |
|
const name = product.stocked ? product.name : ( |
|
<span style={{color: "red"}}>{product.name}</span> |
|
); |
|
const price = product.price; |
|
return ( |
|
<tr> |
|
<td>{name}</td> |
|
<td>{price}</td> |
|
</tr> |
|
); |
|
} |
|
} |
|
|
|
// 可过滤产品列表 |
|
class FilterableProductTable extends React.Component { |
|
constructor(props) { |
|
super(props); |
|
this.state = { |
|
filterText: '', |
|
inStockOnly: false |
|
}; |
|
this.handleFilterTextChange = this.handleFilterTextChange.bind(this); |
|
this.handleInStockChange = this.handleInStockChange.bind(this); |
|
} |
|
|
|
handleFilterTextChange(filterText) { |
|
this.setState({ |
|
filterText: filterText |
|
}); |
|
} |
|
|
|
handleInStockChange(inStockOnly) { |
|
this.setState({ |
|
inStockOnly: inStockOnly |
|
}) |
|
} |
|
|
|
render() { |
|
return ( |
|
<div> |
|
<SearchBar filterText={this.state.filterText} inStockOnly={this.state.inStockOnly} |
|
onFilterTextChange={this.handleFilterTextChange} onInStockChange={this.handleInStockChange}/> |
|
<ProductTable |
|
products={this.props.products} |
|
filterText={this.state.filterText} |
|
inStockOnly={this.state.inStockOnly}/> |
|
</div> |
|
); |
|
} |
|
} |
|
|
|
ReactDOM.render( |
|
<FilterableProductTable products={PRODUCTS}/>, |
|
document.getElementById("root") |
|
); |