上篇說明了 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 依序加入
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);
higher-order-component 有一些命名上的慣例
所以對 withCounter.js 重新整理
import React from 'react';
const withCounter = (WrappedComponent)=>{
class WithCounter extends React.Component{
...
render(){
return(<WrappedComponent ... />)
}
}
return withCounter;
}
export withCounter;
回到 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}
...
/>
)
如果要對 HOC pass 複數
兩元件一樣能作用,並且大幅減少重複性的 code
表示成功使用了 HOC 的概念
可喜可賀
下篇來談談 react router