【本文源址:http://blog.csdn.net/q1056843325/article/details/54755521 轉載請添加該地址】
今天就是春節了,祝各位雞年大吉,心想事成
感覺這兩天錯過了好幾個億
淨往外賠錢了~馬雲爸爸纔給了我2.08. 心塞
不過咱也算是參加過一個兩億的項目了
昨晚發現博客還增加了30+訪問流量
沒想到除夕夜還有這麼多努力的人. 佩服 d===( ̄▽ ̄*)b
好了廢話不多說
使用React構建可搜索產品數據表
是React官網上的一個demo,它不是很難
不過卻能夠很好的映射React的開發流程
而且把我們常用的語法基本都涉及了
可以讓我們對於React有更進一步的理解
React官方傳送門:Thinking in React
UI與JSON
首先我們從我們的UI設計師那裏拿到了UI模擬圖和JSON-API
[
{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"}
];
category是產品類別
price是產品價格
stocked是有無庫存
name是產品名稱
拆分UI視圖
首先我們要做的第一項工作就是拆分UI
把它們拆解成一個個組件,組件中還有子組件
並且賦給它們名字
這個UI可以拆分成五個組件
- FilterableProductTable (黃色)
完整的產品表 - SearchBar (深藍色)
用戶輸入部分 - ProductTable (綠色)
產品完整展示部分 - ProductCategoryRow (天藍色)
產品類別標頭 - ProductRow (紅色)
產品信息
當然你也可以在細拆把ProductTable中的Name和Price拆出來
不過我覺得沒必要搞得這麼複雜
組件層次關係如下:
- FilterableProductTable
- SearchBar
- ProductTable
- ProductCategoryRow
- ProductRow
構建靜態版本
靜態的版本也就是頁面最初應該顯示的版本
構建它不需要複雜的想法,只是代碼多了點
官網上的文檔是這樣說的
In simpler examples, it’s usually easier to go top-down,
and on larger projects, it’s easier to go bottom-up and write tests as you build
意思就是像我們這樣簡單的例子中
通常由頂級層次組件向下來寫更簡單一些
而在大型的項目中
最佳實踐是從下級層次往上寫並且要做必要的測試
那在這裏的demo我們就從FilterableProductTable組件開始寫
var 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'}
];
var FilterableProductTable = React.createClass({
render: function(){
return (
<div>
<SearchBar/>
<ProductTable products={this.props.products}/>
</div>
)
}
});
var SearchBar = React.createClass({
render: function(){
return (
<div>
<input type="text"/><br/>
<input type="checkbox"/>Only show products in stock<br/><br/>
</div>
)
}
});
var ProductTable = React.createClass({
render: function(){
var rows = [];
var lastCategory = null;
this.props.products.forEach(function(product){
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>
<td><strong>Name</strong></td>
<td><strong>Price</strong></td>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
)
}
});
var ProductCategoryRow = React.createClass({
render: function(){
return (
<tr>
<td><strong>{this.props.category}</strong></td>
</tr>
)
}
});
var ProductRow = React.createClass({
render: function(){
var name = this.props.product.stocked ?
this.props.product.name :
<span style={{color:"red"}}>{this.props.product.name}</span>;
return (
<tr>
<td>{name}</td>
<td>{this.props.product.price}</td>
</tr>
)
}
});
ReactDom.render(
<FilterableProductTable products={PRODUCTS}/>,
document.getElementById('root')
)
很好的體現了React單向數據流的特點
將JSON數據交給父級
然後父級再講數據傳遞下去
這裏比較關鍵的代碼就是ProductTable中的這部分了
var rows = [];
var lastCategory = null;
this.props.products.forEach(function(product){
if(product.category !== lastCategory){
rows.push(<ProductCategoryRow category={product.category} key={product.category}/>);
}
rows.push(<ProductRow product={product} key={product.name}/>);
lastCategory = product.category;
});
利用了數組的形式將靜態列表的組件項存儲下來
使用變量lastCategory,噹噹前遍歷的product中category與lastCategory不同時
就向數組中添加ProductCategoryRow組件
售罄產品過濾
我們先來考慮點擊那個複選框來重置是否顯示售罄產品過濾
很容易的就可以想到必須要設置一個狀態
這個狀態就是是否只顯示有庫存的產品(或者不顯示售罄產品)
然後爲複選框綁定change事件改變狀態
var FilterableProductTable = React.createClass({
getInitialState: function(){
return {
inStockOnly: false
}
},//設置初始狀態:產品默認展示全部
checkHandler: function(){
this.setState({
inStockOnly: !this.state.inStockOnly
});
},//複選框要綁定的事件處理函數:改變inStockOnly狀態
render: function(){
return (
<div>
<SearchBar checkHandler={this.checkHandler}/> //將事件處理函數作爲數據傳遞給子級
<ProductTable products={this.props.products} inStockOnly={this.state.inStockOnly}/>
//將狀態state作爲屬性props傳遞給子級
</div>
)
}
});
var SearchBar = React.createClass({
render: function(){
return (
<div>
<input type="text"/><br/>
<input type="checkbox" onChange={this.props.checkHandler}/>Only show products in stock<br/><br/>
//爲複選框綁定change事件處理函數
</div>
)
}
});
var ProductTable = React.createClass({
render: function(){
var rows = [];
var lastCategory = null;
var products = this.props.inStockOnly ?
this.props.products.filter(function(product){
return product.stocked;
}) : this.props.products;
//通過判斷狀態inStockOnly來決定是否過濾products數組
products.forEach(function(product){
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>
<td><strong>Name</strong></td>
<td><strong>Price</strong></td>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
)
}
});
關鍵字過濾產品
進度已經過去一大半了
剩下一個問題就是我們在輸入框中輸入字符時
同樣需要對產品進行“過濾”
現在我們需要另外的狀態——輸入框字符改變
還需要一個事件處理函數來改變這個狀態
var FilterableProductTable = React.createClass({
getInitialState: function(){
return {
inStockOnly: false,
filterText: '' //表示輸入框中字符
}
},
checkHandler: function(){
this.setState({
inStockOnly: !this.state.inStockOnly
});
},
textHandler: function(text){
this.setState({
filterText: text
});
}, //輸入框字符改變狀態隨之改變,但是還不能獲取輸入框中字符,所以設置一個參數test
render: function(){
return (
<div>
<SearchBar checkHandler={this.checkHandler} textHandler={this.textHandler}/>
//將事件處理函數作爲數據傳遞給SearchBar組件
<ProductTable products={this.props.products} inStockOnly={this.state.inStockOnly} filterText={this.state.filterText}/>
//將filterText狀態傳遞給ProductTable組件
</div>
)
}
});
var SearchBar = React.createClass({
Handler: function(){
this.props.textHandler(this.refs.input.value);
}, //爲了將獲取的輸入框內字符傳入textHandler作爲參數,外部包裝一個函數
render: function(){
return (
<div>
<input type="text" ref="input" onChange={this.Handler}/><br/>
// 綁定change事件處理函數
<input type="checkbox" onChange={this.props.checkHandler}/>Only show products in stock<br/><br/>
</div>
)
}
});
var ProductTable = React.createClass({
render: function(){
var rows = [];
var lastCategory = null;
var products = this.props.products;
var inStockOnly = this.props.inStockOnly;
var filterText = this.props.filterText;
products = inStockOnly ?
products.filter(function(product){
return product.stocked;
}) : products;
products = filterText ?
products.filter(function(product){
return product.name.indexOf(filterText) !== -1;
}) : products;//通過字符限制一步過濾
products.forEach(function(product){
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>
<td><strong>Name</strong></td>
<td><strong>Price</strong></td>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
)
}
});
完整版本
完整的腳本代碼如下
var React = require('react');
var ReactDom = require('react-dom');
var 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'}
];
var FilterableProductTable = React.createClass({
getInitialState: function(){
return {
inStockOnly: false,
filterText: ''
}
},
checkHandler: function(){
this.setState({
inStockOnly: !this.state.inStockOnly
});
},
textHandler: function(text){
this.setState({
filterText: text
});
},
render: function(){
return (
<div>
<SearchBar checkHandler={this.checkHandler} textHandler={this.textHandler}/>
<ProductTable products={this.props.products} inStockOnly={this.state.inStockOnly} filterText={this.state.filterText}/>
</div>
)
}
});
var SearchBar = React.createClass({
Handler: function(){
this.props.textHandler(this.refs.input.value);
},
render: function(){
return (
<div>
<input type="text" ref="input" onChange={this.Handler}/><br/>
<input type="checkbox" onChange={this.props.checkHandler}/>Only show products in stock<br/><br/>
</div>
)
}
});
var ProductTable = React.createClass({
render: function(){
var rows = [];
var lastCategory = null;
var products = this.props.products;
var inStockOnly = this.props.inStockOnly;
var filterText = this.props.filterText;
products = inStockOnly ?
products.filter(function(product){
return product.stocked;
}) : products;
products = filterText ?
products.filter(function(product){
return product.name.indexOf(filterText) !== -1;
}) : products;
products.forEach(function(product){
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>
<td><strong>Name</strong></td>
<td><strong>Price</strong></td>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
)
}
});
var ProductCategoryRow = React.createClass({
render: function(){
return (
<tr>
<td><strong>{this.props.category}</strong></td>
</tr>
)
}
});
var ProductRow = React.createClass({
render: function(){
var name = this.props.product.stocked ?
this.props.product.name :
<span style={{color:"red"}}>{this.props.product.name}</span>;
return (
<tr>
<td>{name}</td>
<td>{this.props.product.price}</td>
</tr>
)
}
});
ReactDom.render(
<FilterableProductTable products={PRODUCTS}/>,
document.getElementById('root')
)
UI視圖切分爲組件模塊
將JSON數據放入父級組件
再將數據props流入子級組件
設置狀態位,然後通過事件處理函數改變狀態state
state改變,觸發DOM的不斷渲染
這個例子詮釋了React的組件化、單向數據流的特點