首先編寫一下咱們的公共組件react
goodsItem.js
設計模式
// 單個商品
import React from 'react';
const GoodsItem = props => {
const { goods: {name, num, price}, handleSub, handleAdd } = props;
return <div className="goods-item">
{name}
<button onClick={() => handleSub()}>-</button>
<span>{num}</span>
<button onClick={() => handleAdd()}>+</button>
價格:{price}
</div>
};
export default GoodsItem;
複製代碼
goodList.js
api
// 商品列表
import React from 'react';
import GoodsItem from './goodsItem';
class GoodsList extends React.Component {
constructor(props) {
super(props);
this.state = {
goodsData: []
}
}
componentDidMount() {
const { goodsData } = this.props;
this.setState({ goodsData: goodsData});
}
handleAddorSub(id, type) {
let { goodsData } = this.state;
let newGoods = goodsData.reduce((newData, goods) => {
if (goods.id === id) {
goods.num = type === '+' ? goods.num + 1 : goods.num - 1;
}
newData.push(goods);
return newData;
}, [])
this.setState({ goodsData: newGoods })
}
render() {
const { goodsData } = this.state;
return (
<div className="goods-list">
{goodsData.map(goods =>
<GoodsItem
key={goods.id}
goods={goods}
handleAdd={() => this.handleAddorSub(goods.id, '+')}
handleSub={() => this.handleAddorSub(goods.id, '-')}
/>
)}
</div>
);
}
};
export default GoodsList;
複製代碼
咱們通常編寫組件,都會這麼去作,list包裹item,循環展現item。數據放在list組件中,item做爲一個無狀態組件,只作他的展現。bash
數據交互經過props傳遞,點擊+-
會改變購物車裏的數據。函數
如今需求來了,雙12來了(就在昨日),全部商品8折優惠。ui
這意味着咱們須要修改goodsData中全部商品的價格。this
這並不難,我葉良辰有100種方法能夠修改商品數據。找個可行的生命週期,好比componentDidMount
中修改list組件state.goodsData
就好了。spa
若是每次修改都直接修改goodList組件,也是能夠的,大不了多傳幾個props來判斷須要打折仍是修改商品名稱等等。設計
可是有些需求是交叉的,若是一直這樣寫,長此以往組件會變得愈來愈臃腫,最後爆炸。code
好的解決方案應該是goodsList不去動他,外加一層來進行包裝,實現咱們的邏輯。
這樣既保證了goodsList的純
,又能實現邏輯的複用。可謂一舉兩得。
用兩種組件設計模式能夠幫助到咱們。
咱們調用公共組件的方法以下:
<GoodsList goodsData={goodsData} />
複製代碼
咱們用renderProps模式實現打折商品組件:
<DiscountedGoodsList goodsData={goodsData}>
{(data) => <GoodsList goodsData={(data)} />}
</DiscountedGoodsList>
複製代碼
能夠看到,DiscountedGoodsList的子組件是一個函數,那麼一個函數是怎麼渲染成組件的?
再來看看DiscountedGoodsList組件的代碼:
const DiscountedGoodsList = props => {
// 8折優惠邏輯
const setRenderPropsData = (data) => {
let renderPropsData = data.reduce((array, goods) => {
let obj = {};
for (let k in goods) {
obj[k] = k === 'price' ? (goods[k] * .9).toFixed(2) : goods[k];
}
array.push(obj);
return array;
}, []);
return renderPropsData;
}
let goodsData = setRenderPropsData(props.goodsData);
return (
<React.Fragment>
{props.children(goodsData)}
</React.Fragment>
);
}
複製代碼
setRenderPropsData
的做用是實現8折優惠邏輯,將全部商品價格調整。
而後調用props.children這個api,獲得在上面咱們編寫的函數。
props.children也就是函數(data) => <GoodsList goodsData={(data)} />
的引用。
將處理後的數據goodsData做爲參數執行,最終返回<GoodsList />
組件,這就是renderProps模式。
之後咱們須要調用價格優惠的商品列表組件,直接調用DiscountedGoodsList
便可。
renderProps的模式實現了邏輯的共用,且對GoodsList
組件毫無反作用,從而達到咱們的目的。
編寫咱們的高階組件以下:
const BrandGoodsList = (Component, goodsData) => {
// 品牌商品邏輯
const setRenderPropsData = (data) => {
let renderPropsData = data.reduce((array, goods) => {
let obj = {};
for (let k in goods) {
obj[k] = k === 'name' ? goods[k] + '【品牌】' : goods[k];
}
array.push(obj);
return array;
}, []);
return renderPropsData;
}
let brandGoodsData = setRenderPropsData(goodsData);
return <Component goodsData={brandGoodsData} />
}
複製代碼
BrandGoodsList
組件的邏輯就是給商品名稱加上【品牌】
的標示,區分商品。
高階組件的調用比較簡單:{BrandGoodsList(GoodsList, goodsData)}
直接執行返回組件,而後渲染。
實現了兩種模式,如今咱們將他們一塊兒用,實現一個既打折,又是品牌商品的組件。
<DiscountedGoodsList goodsData={goodsData}>
{(data) => BrandGoodsList(GoodsList, data)}
</DiscountedGoodsList>
複製代碼
挺舒服的吧,隨時分離,隨時結合。正是高內聚、低耦合本人啊。
最後,完整的調用看一下:
<div className="App">
基本商品列表組件:
<GoodsList goodsData={goodsData} />
<br />
打8折商品列表組件(renderProps模式實現):
<DiscountedGoodsList goodsData={goodsData}>
{(data) => <GoodsList goodsData={(data)} />}
</DiscountedGoodsList>
<br />
品牌商品列表組件(高階組件模式實現):
{BrandGoodsList(GoodsList, goodsData)}
<br />
既是打折商品,又是品牌商品(兩種模式複用)
<DiscountedGoodsList goodsData={goodsData}>
{(data) => BrandGoodsList(GoodsList, data)}
</DiscountedGoodsList>
</div>
複製代碼
以爲有幫助的點個贊,甚至能夠關注一波哦~