【面試進階】React組件設計模式(一)

首先編寫一下咱們的公共組件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.jsapi

// 商品列表

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的,又能實現邏輯的複用。可謂一舉兩得。

用兩種組件設計模式能夠幫助到咱們。

一. renderProps 模式

renderProps實際上是利用組件的props.children api,將函數當成組件的一種寫法。

咱們調用公共組件的方法以下:

<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組件毫無反作用,從而達到咱們的目的。

二. HOC(高階組件)模式

所謂的高階組件,其實就是一個函數,該接受component爲參數,返回一個處理後的component。

編寫咱們的高階組件以下:

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>
複製代碼

總結:

一、renderProps 模式的核心是props.children的使用。

二、高階組件的寫法看起來更舒服,比較受歡迎。

三、兩種模式解決的問題:複用邏輯、不污染底層組件。

以爲有幫助的點個贊,甚至能夠關注一波哦~

相關文章
相關標籤/搜索