第二步:在 React 中建立一个静态版本
不要使用 state 来建立静态版本,因为state是保留给互动性,也就是会随时间改变的资料。可以从最上层往下层写,但在大型开发专案中,由下往上边写边测试是比较安全的因为这是静态的版本,所以由最高层级的Component(FilterableProductTable)来接收资料库的数据,并使用props向下传递数据库的传递 : FilterableProductTable --> ProductTable --> ProductCategoryRow / ProductRowReactDOM:
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'} ]; ReactDOM.render( //将数据库藉由props传入最高层级Component <FilterableProductTable products={PRODUCTS} />, document.getElementById('root') //将结果渲染到HTML中 );
FilterableProductTable:
作为最高层级的Component,接收数据库数据并将他利用props分给Sub Components
class FilterableProductTable extends React.Component { render() { return ( <div> <SearchBar /> {/* 将从父层传递的数据库传递给子层(ProductTable) */} <ProductTable products={this.props.products} /> </div> ); } }
SearchBar :
class SearchBar extends React.Component { render() { return ( <form> <input type="text" placeholder="Search..." /> <p> <input type="checkbox" /> {' '} Only show products in stock </p> </form> ); } }
ProductTable :
第二层Component,接收最高层级Component FilterableProductTable的数据库资料(props)
class ProductTable extends React.Component { render() { const rows = []; let lastCategory = null; /* 将数据库阵列内每个元素传入function,function会先判断category是否与前一个一样,若不是的便会将"ProductCategoryRow"加入到row阵列中并把"category" 与 "key"利用props传给子层; 若一样便会把"ProductRow"加入到row阵列并将"product" 与 "key"利用props传给子层 */ //forEach : 将阵列内的每个元素,皆传入并执行给定的函式一次。 this.props.products.forEach((product) => { if (product.category !== lastCategory) { //push : 加一个或多个元素至阵列的末端 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> ); } }
可以藉由console.log观看到row中的数据,将类别与商品名称分类
//---------------------------------- 类别 ------------------------------------------//0: {$$typeof: Symbol(react.element), key: "Sporting Goods", ref: null, props: {…}, type: ƒ, …}//---------------------------------- 商品 ------------------------------------------//1: {$$typeof: Symbol(react.element), key: "Football", ref: null, props: {…}, type: ƒ, …}2: {$$typeof: Symbol(react.element), key: "Baseball", ref: null, props: {…}, type: ƒ, …}3: {$$typeof: Symbol(react.element), key: "Basketball", ref: null, props: {…}, type: ƒ, …}//---------------------------------- 类别 ------------------------------------------//4: {$$typeof: Symbol(react.element), key: "Electronics", ref: null, props: {…}, type: ƒ, …}//---------------------------------- 商品 ------------------------------------------//5: {$$typeof: Symbol(react.element), key: "iPod Touch", ref: null, props: {…}, type: ƒ, …}6: {$$typeof: Symbol(react.element), key: "iPhone 5", ref: null, props: {…}, type: ƒ, …}7: {$$typeof: Symbol(react.element), key: "Nexus 7", ref: null, props: {…}, type: ƒ, …}
ProductCategoryRow :
第三层Component,接收父层(第二层Component ProductTable)所传递的数据库(props)
class ProductRow extends React.Component { render() { const product = this.props.product; //判断数据库中的stocked是否为true,若是则直接输出商品名称,若为否则将商品名称改为红色 const name = product.stocked ? product.name : <span style={{color: 'red'}}> {product.name} </span>; return ( <tr> <td>{name}</td> <td>{product.price}</td> </tr> ); } }
ProductRow :
第三层Component,接收父层(第二层Component ProductTable)所传递的数据库(props)
class ProductCategoryRow extends React.Component { render() { const category = this.props.category; return ( <tr> {/* colSpan = "2"将<th>属性输出的元件跨两格 */} <th colSpan="2"> {category} </th> </tr> ); } }