iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Modern Web

為期 30 天的 react 大冒險系列 第 24

react 大冒險-higher order component-day 20-2

  • 分享至 

  • xImage
  •  

上篇說明了 higher-order-component 的概念
用一個簡單的案例作為例子

開新檔案,名為 ClickerCounter.js
希望點擊元件上的按鈕,達成更新頁面上點擊次數

import React from 'react';

class ClickerCounter extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            updateTimes: 0
        }
        this.incrementCount = this.incrementCount.bind(this);
    }
    incrementCount(){
        this.setState(oldState=>{
            return { updateTimes : oldState.updateTimes+1 }
       })
    }
   render(){
       return(
           <>
               <h2>Clicker Counter</h2>
               <button onClick={incrementCount}>click {updateTimes} times</button>
           </>)
   } 
}
export default ClickerCounter;

再新增 名為 HoverCounter.js 的檔案
這次要達成 滑鼠滑入區塊後更新次數

import React from 'react';

class ClickerCounter extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            updateTimes: 0
        }
        this.incrementCount = this.incrementCount.bind(this);
    }
    incrementCount(){
        this.setState(oldState=>{
            return { updateTimes : oldState.updateTimes+1 }
       })
    }
   render(){
       return(
           <>
               <h2>Clicker Counter</h2>
               <button onMouseOver={incrementCount}>click {updateTimes} times</button>
           </>)
   } 
}
export default ClickerCounter;

這時候會發現兩個 component 中的 incrementCount 跟 updateTimes 邏輯上非常雷同
將這部分抽出來,開新檔案 withCounter.js

import React from 'react';

const UpdatedComponent = (OriginalComponent)=>{
    class NewComponent extends React.Component{
        constructor(props){
            super(props);
            this.state = {
               updateTimes : 0
            }
            this.incrementCount = this.incrementCount.bind(this);
        }
        incrementCount(){
            this.setState(oldSt=>{ 
                return{ updateTimes: oldSt.updateTimes+1 } 
            })
        }
        render(){
            const { updateTimes } = this.state;
            return(
                <OriginalComponent 
                    updateTimes={updateTimes} 
                    incrementCount={this.incrementCount}
                />
            )
        }
    }
    return NewComponent;
}
export default UpdatedComponent;

回到 HoverCounter 跟 ClickerCounter 對這兩個 component 依序加入

  1. import UpdatedComponent
  2. 在 export 的地方加入 UpdatedComponent,將 component 作為 parameter pass 進 UpdatedComponent
import React from 'react';
import UpdatedComponent from './withCounter';

class ClickerCounter extends React.Component {
   render(){
       return(
           <>
               <h2>Clicker Counter</h2>
               <button onMouseOver={incrementCount}>click {updateTimes} times</button>
           </>)
   } 
}
export default UpdatedComponent(ClickerCounter);

HOC 的命名慣例

higher-order-component 有一些命名上的慣例

  • 通常 export 的內容 會跟檔名相同 (小寫開頭)
  • 傳入的 OriginalComponent 可以改成自己想要的名字
  • 新產生的 component 也跟檔名相同,但是是 class component,所以是大寫開頭

所以對 withCounter.js 重新整理

import React from 'react';
const withCounter = (WrappedComponent)=>{
    class WithCounter extends React.Component{
        ...
        render(){
            return(<WrappedComponent  ... />)
        }
    }
    return withCounter;
}

export withCounter;

在 HOC 內 記得 pass down props

回到 App.js,對 ClickCounter component 定義名為 name 的 prop
在 ClickCounter.js 將 name prop 顯示在元件中

App.js

return(
    ...
    <ClickerCounter name={'201008'} />
    ...
)

ClickerCounter.js

return (
    ...
    <h2>Clicker Counter {name}</h2>
    ...
)

重整後,卻會發現 ClickCounter 的 name prop 並不會顯示
打開 developer tool 發現

因為 HOC 的關係,原本傳到 ClickCounter 的 prop 實際上傳到 WithCounter(也就是 HOC 新建立的 component ) 裡去了
要從該 component 往下傳

使用 spread operator 打散所有 props 往下傳

return (
    <WrappedComponent 
    ...
    {... props}
    ...
    />
)

傳複數的 parameter

如果要對 HOC pass 複數

兩元件一樣能作用,並且大幅減少重複性的 code
表示成功使用了 HOC 的概念
可喜可賀

下篇來談談 react router


上一篇
react 大冒險-higher order component-day 20-1
下一篇
react 大冒險-react router-day 21-1
系列文
為期 30 天的 react 大冒險30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言