---
# System prepended metadata

title: 面試考題 2024 - HOC是什麼（實作）
tags: [面試問題, 練習問題, '2024']

---

面試考題 2024 - HOC是什麼（實作）
===

![image](https://hackmd.io/_uploads/ryWGwvg70.png)


---
###### tags: `面試問題`, `練習問題`, `2024`

HOC 完整名稱是 Higher-Order Component ，簡單地解釋是一種基於React的組合特性而形成的設計模式。
沒錯！我認為每一位 JR 都必須修練的技術，通常都會看到 SR 或者 TechLead 說要製作更加彈性的 Component 供多個網頁使用，一來容易整合，一來是減少多餘的重複性作業。

比較官方的寫法： **HOC是一個函數（function）**，它接受一個組件作為參數，並返回一個新的組件。（簡單說就是給一個jsx.element 放進這個function 然後強化以後，成為一個全新的 jsx.element）。 **它不是組件本身**，而是一個創建組件的函數。 HOC 的目的是重用組件邏輯，特別是那些在**多個組件中共享的邏輯**。
![image](https://hackmd.io/_uploads/HkXHb7XQA.png)

### HOC的用法：
* **增強組件的功能**： 可以為組件添加額外的屬性或邏輯
* **條件渲染**： 根據某些條件改變組件的行為或樣式
* **訪問控制**： 例如，限制某些組件的訪問。
* **狀態管理與數據綁定**： 例如，連接到Redux 或 Context API。


## HOC實作示範：

```jsx!
// 這是一個簡單的組件
// 然後要從localStorage 拿到data裡的name
// 放入這個component裡。
const SimpleComponent = props => <div>Hello {props.name}!</div>

function withStorage(component){
    return function EnhancedComponent(props) {
        const savedData = localStorage.getItem('data');
        return <Component {...props} data={savedData} />
    }
}

const SimpleComponentWithStorage = withStorage(SimpleComponent);

function App(){
    return <SimpleComponentWithStorage name="Gordon" />
}
```

### 解說：
* HOC的原理設計是 withStorage 必須是返回成一個新的Component。
* HOC設計是為了達到封裝可復用的邏輯或行為精神。
* 跟性能問題無關，而是為了保持HOC的正確抽象，靈活性和可復永用性而設計。

### 過程分解：
1. 獲取數據：
    * 在**EnhancedComponent**的函數體內，**localStorage.getItem('data')** 被調用來獲取存儲在本地存儲中的數據。這個 **data** 被視為一個要添加到組件中的新屬性。

2. 傳遞原始 props：
    * 使用 **{...props}** 這種展開操作符的方式，可以確保所有傳遞給**EnhancedComponent的 props （例如 name）** 都會被原樣傳遞給內部的 Component。 這確保了增強組件的行為與原始組件盡**可能保持一致，同時增加了額外的功能或數據**。 

3. 添加新屬性：
    * **data={savedData}** 這一行代碼將從 **localStorage 獲取的數據作為 data** 屬性傳遞給 Component。這樣，增強後的組件除了原始的 props 外，還能**接收到新的 data 屬性**。

### 這裡的總結：

其實HOC是在一個完成的功能，可能是JSX.element 完成了設計，後來被要求要額外接一個功能啦，可能要新增某些呈現啦，那就很適合用 HOC 來規劃下和再不需要太大動到原始程式。


## 進入進階版！

```jsx!
//權限驗證 HOC
function withAuthorization(Component){
    return function WrappedComponent(props){
        if(!props.user.hasPermission){
            return <div>No access</div>;
        }
        return <Component {...props} />
    };
}

//數據獲取 HOC
function withUserData(Component){
    return function WrappedComponent(props){
        const [userData, setUserData] = useState(null);
        useEffect(()=>{
            fetchUserData(props.userId).then(data=>
                setUserData(data));
        },[props.userId]);
        
        if(!userData){
            return <div>Loading ...</div>
        }
        return <Component {...props} userData={userData}/>
    };
}

const EnhancedUserProfile = withUserData(withAuthorization(UserProfile));
```
* 使用HOC的關鍵 是它允許你保持組件的關注點分離和單一職責原則。
* 它使得組件保持見解，而功能性的增加則通過外部封裝實現。
* 這樣即使需求變動頻繁，也能靈活應對，而不會影響到組件的核心邏輯。
* 這種模式提高了代碼的可維護性，可擴展性和再利用性。
---
## 總結
  
  當你通過HOC為組件添加新的props 或 狀態時，組件應該能夠使用這些新增的 props 來更新其 UI。
  確保組件能夠響應這些props的比拿話是使用HOC時的一個重要考慮。我覺得最直觀的做法可以理解為你有一組起始的fetching然後要整合以後再去做rendering UI的部分，那個fetching就可以分離到HOC完成，然後UI 就單純做 UI。可是這裡有個新手的大忌就是記得props不要傳超過第二層，這樣會造成 hydration 的問題喔。
  當你的HOC寫的很細的話，如果遇到page UI需要用到相同的對象就可以用套的方式套起來！
  希望我分享的這篇能幫助你去理解更好的寫法，當然學會了HOC並且運用在專案上或者 side，都可以在面試上炫起來喔！我們下篇再見！
![image alt](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExYXg4Znc1MDNtYnZydXE0aDNxNmh0dnhscjU3YzhpcmJjaHVwMjJjaiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/fxe8v45NNXFd4jdaNI/giphy.gif)
